Floyd求最小环
题意:
- 给定一个数组a.
- 如果
a
[
i
]
&
a
[
j
]
!
=
0
a[i]\&a[j]!=0
a[i]&a[j]!=0 则说明
i
和
j
i和j
i和j之间有一条无向边,现在询问这个图的最小环的长度是多少;
数据范围:
n
≤
100000
,
0
≤
a
[
i
]
≤
1
0
18
n \leq 100000, 0\leq a[i] \leq10^{18}
n≤100000,0≤a[i]≤1018
前置技能: floyd求最小环 一颗勇敢而细致的心(看到数据范围不要怕不能暴力)
Tutorial: long long 看成二进制最多有63位, 如果存在有一位为1的数的数量大于2,那么最小环的数量就可以直接得到为3(画个图), 那么假设每个a[i]只出现一位, 出现每个位上都是2的情况最多有63*2 = 126 个词, 如果有效词大于这个数就直接是上面的情况了, 所以n的大小就被我们限定在126以内了, 剩下的就是以63为结点建图跑floyd了 (注意忽略掉0)
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rof(i, a, b) for (int i = (a); i > (b); --i)
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl;
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair<int, int>
const int maxm = 1e3+10, maxn = 1e5 + 10;
ll dis[maxm][maxm], e[maxm][maxm];
int n, cnt;
ll a[maxn];
ll nxt(){
ll ret;
scanf("%lld", &ret);
return ret;
}
signed main(){
n = nxt();
_rep(i, 1, n){
ll tmp = nxt();
if(tmp)a[++cnt] = tmp;
}
if(cnt>= 129){
cout << "3" << endl;
return 0;
}
n = cnt;
_rep(i, 1, n){
_rep(j, 1, n){
dis[i][j] = e[i][j] = (i == j ? 0 : oo);
}
}
_rep(i, 1, n){
_rep(j, 1, n){
if(i == j)continue;
if(a[i] & a[j])dis[i][j] = dis[j][i] = e[i][j] = e[j][i] = 1;
}
}
ll ans = oo;
_rep(k, 1, n){
_rep(i, 1, k-1){
_rep(j, i+1, k-1){
ans = min(ans, dis[i][j] + e[i][k] + e[k][j]);
}
}
_rep(i,1,n){
_rep(j, 1, n){
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
if(ans == oo)cout << "-1" << endl;
else cout << ans << endl;
}