题目连接
题目大意
有n个数可以看做是n个点,如果ai & aj !=0,那么点 i 和点 j 可以连一条无向边。问这个图出点数最小的环的大小事多少,如果没有环就输出-1;
解题思路
如果 x&y != 0 那么x的二进制和y的二进制至少有一位是1,所以如果这n个数中有3个数的二进制都是1,那么这三个数可以围成一个环。
其他情况就是每一位最多只有两个数是1,那么最多是64*2个数,可以建边跑floyd,跑最小环输出答案
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
const int N=1e5+5;
long long a[N],b[N];
int bu[N];
vector<int>v[70];
int inf=0x3f3f3f;
int e[1005][1005],dis[1005][1005];
void F(long long x,int a)
{
int cnt=1;
while(x)
{
if(x%2)
{
v[cnt].push_back(a);
}
x/=2;
cnt++;
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
F(a[i],i);
}
int flag1=0;
for(int i=0; i<=65; i++)
{
int k=v[i].size();
if(v[i].size()>=3)
flag1=1;
}
if(flag1)
{
printf("3\n");
}
else
{
int cnt=0;
map<int,int>mp;
for(int i=0; i<=65; i++)
{
if(v[i].size()==2)
{
int uu=v[i][0],vv=v[i][1];
// printf("%d %d %d\n",i,uu,vv);
if(!mp[uu])
mp[uu]=++cnt;
if(!mp[vv])
mp[vv]=++cnt;
// printf("%d %d\n",mp[uu],mp[vv]);
}
}
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=cnt;j++)
{
if(i==j)
e[i][j]=0;
else
e[i][j]=dis[i][j]=inf;
}
}
for(int i=0;i<=65;i++)
{
if(v[i].size()==2)
{
int uu=mp[v[i][0]],vv=mp[v[i][1]];
//printf("%d %d\n",uu,vv);
e[uu][vv]=e[vv][uu]=1;
dis[uu][vv]=dis[vv][uu]=1;
}
}
int res=inf;
for(int k=1;k<=cnt;k++)
{
for(int i=1;i<k;i++)
for(int j=i+1;j<k;j++)
res=min(res,dis[i][j]+e[i][k]+e[k][j]);
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
if(res<inf)
printf("%d\n",res);
else
printf("-1\n");
}
return 0;
}