题意:给你一个长度为n的序列,看成是图上的n个结点,如果结点i,j连通当且仅当ai & aj != 0,问形成的图是否成环,且最小的环的大小是多少?
思路:我们考虑最大长度不构成环的n,1 1 2 2 4 4 8 8 ...2^63-1 2^63-1,发现n最大是128(前提是序列中的数都不为0),说明超过128一定存在一个环,且环的大小为3.n<=128时,建图跑Floyd求最小环即可
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 2e2;
const int Inf = 1e6;
long long x;
int dis[N][N], f[N][N];
vector<long long> A;
int Floyd(int n) {
int path = Inf;
for(int k = 0; k < n; k += 1) {
for(int i = 0; i < k; i += 1) {
for(int j = 0; j < i; j += 1)
path = min(path, dis[i][k] + dis[k][j] + f[i][j]);
}
for(int i = 0; i < n; i += 1) {
for(int j = 0; j < n; j += 1)
f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
}
}
return path != Inf ? path : -1;
}
void init(int n) {
for(int i = 0; i < n; i += 1) {
dis[i][i] = f[i][i] = Inf;
for(int j = i + 1; j < n; j += 1) {
dis[i][j] = dis[j][i] = Inf;
f[i][j] = f[j][i] = Inf;
}
}
}
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < n; i += 1) {
scanf("%lld", &x);
if(x)
A.push_back(x);
}
if(A.size() > 128)
printf("3\n");
else {
memset(dis, N, sizeof(dis));
int vi = A.size();
init(vi);
for(int i = 0; i < vi; i += 1) {
for(int j = 0; j < vi; j += 1) {
if(A[i]&A[j]) {
f[i][j] = f[j][i] = 1;
dis[i][j] = dis[j][i] = 1;
}
}
}
printf("%d\n", Floyd(vi));
}
return 0;
}