题意:
给n个数,(a[1]-a[n]),如果如果i!=j且(a[i]&a[j])!=0,则在i与j之间建边
求图的最小环
(无向图最小环至少三个顶点)
分析:
如果二进制位的某一位为1的数的数量>=3那么答案就是3
否则不为0的数最多只有2*63=126个(long long除去符号位只有63位有效)
可以反推出如果不为0的数大于126个答案就是3
否则直接暴力求最小环就行了
最小环求法很多,这里用的floyd(不具体介绍了)
另外:因为可能有会三个inf相加,所以inf的值不能太大(3个0x3f3f3f3f会爆int)
code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
typedef long long ll;
const int inf=300;
using namespace std;
const int maxm=1e5+5;
int cnt;
ll a[maxm];
int d[205][205];
int g[205][205];
int ans=inf;
void input(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
ll t;
cin>>t;
if(t)a[++cnt]=t;
}
if(cnt>126){
puts("3");
exit(0);
}
}
void build(){
for(int i=1;i<=cnt;i++){
for(int j=i+1;j<=cnt;j++){
if(a[i]&a[j])g[i][j]=g[j][i]=d[i][j]=d[j][i]=1;
else g[i][j]=g[j][i]=d[i][j]=d[j][i]=inf;
}
}
}
void floyd(){
for(int k=1;k<=cnt;k++){
for(int i=1;i<=k-1;i++){
for(int j=i+1;j<=k-1;j++){
ans=min(ans,d[i][j]+g[i][k]+g[k][j]);
}
}
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
if(ans==inf){
puts("-1");
}else{
printf("%d\n",ans);
}
}
int main(){
ios::sync_with_stdio(0);
input();
build();
floyd();
return 0;
}