题意:有n个人,m组关系。现在想要从这n个人中选3个人。这3个人必须满足的条件:1)这3个人必须相互认识 2)这3个人的识别度的总和最小(一个人的识别度为:除了另外两人认识的人的数,三个人的识别度相加最小)
如果存在,则输出识别度总和最小的那个值,如果不存在,则输出-1
位运算压缩,将一个点能直接相连的其他点都压缩,然后直接枚举点,然后通过点枚举边,判断共同点就可。
复杂度O(nm)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <set> #include <vector> #include <map> #include <queue> #include <set> #include <algorithm> #include <limits> using namespace std; typedef long long LL; const int MAXN=1e+4; const int INF = numeric_limits<int>::max(); const LL LL_INF= numeric_limits<LL>::max(); struct Edge { int to,next; Edge(){} Edge(int _to,int _next):to(_to),next(_next){} }e[MAXN]; int head[MAXN],tot; void init(){ memset(head,-1,sizeof(head)); tot=0; } void AddEdge(int u,int v){ e[tot]=Edge(v,head[u]); head[u]=tot++; e[tot]=Edge(u,head[v]); head[v]=tot++; } int bit[MAXN][MAXN/32],n,m,du[MAXN]; void print(int x){ for(int i=0;i<32;i++) printf("%d",(x>>(31-i))&1); puts(""); } int main() { while(~scanf("%d%d",&n,&m)){ memset(bit,0,sizeof(bit)); memset(du,0,sizeof(du)); init(); for(int i=0;i<n;i++)bit[i][i/32]=(1<<(31-i%32)); for(int i=0,x,y;i<m;i++){ scanf("%d%d",&x,&y); AddEdge(--x,--y); ++du[x];++du[y]; bit[x][y/32]|=(1<<(31-y%32)); bit[y][x/32]|=(1<<(31-x%32)); } int ans=-1; for(int u=0;u<n;u++){ for(int i=head[u];~i;i=e[i].next){ int v=e[i].to; int minn=-1; for(int j=0;j<=n/32;j++){ int t1=bit[u][j]; int t2=bit[v][j]; if(j==u/32)t1^=(1<<(31-u%32)); if(j==v/32)t2^=(1<<(31-v%32)); int t3=t1&t2; if(t3){ for(int k=0;k<32;k++) if((t3>>(31-k))&1){ if(minn==-1)minn=j*32+k; else if(du[j*32+k]<du[minn])minn=j*32+k; } } } if(~minn){ if(~ans)ans=min(du[u]+du[v]+du[minn]-6,ans); else ans=du[u]+du[v]+du[minn]-6; } } } printf("%d\n",ans); } return 0; }
|