题意:有n个人,m组关系。现在想要从这n个人中选3个人。这3个人必须满足的条件:1)这3个人必须相互认识 2)这3个人的识别度的总和最小(一个人的识别度为:除了另外两人认识的人的数,三个人的识别度相加最小)
如果存在,则输出识别度总和最小的那个值,如果不存在,则输出-1

位运算压缩,将一个点能直接相连的其他点都压缩,然后直接枚举点,然后通过点枚举边,判断共同点就可。
复杂度O(nm)O(nm)

//author: CHC
//First Edit Time: 2015-09-08 19:32
#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));
//print(bit[0][0]);
//print(bit[1][0]);
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));
}
//print(bit[0][0]);
//print(bit[1][0]);
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){
//printf("%d %d %d\n",u,v,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;
}