【floyed求最小环】【鸽巢原理】D. Shortest Cycle
给定n个数,若存在两个数,它们相与的结果不为0,则在它们之间连上一条线,求在这些操作后最小环的大小。
观察一下,每一个数字是小于等于1e18的,也就是每一个数字在二进制下最多只需要60位就能表达清楚。
同时若某一个二进制位置为1的数的个数大于等于3,则它们本身会形成一个三元环(两两连线)
而当达到121个数字后,必然存在三个数字它们能够两两连接(鸽巢定理)
同时0与上任何数字都是0,是一个孤立点。
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
using namespace std;
const int N = 125,M = 6E5+10;
int n,m;
vector<ll > num;
int f[N][N],road[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
ll x;
cin>>x;
if(x) num.push_back(x);
}
if(num.size()>=121) cout<<3;
else
{
int nums = num.size();
for(int i=0;i<nums;i++)
for(int j=0;j<nums;j++)
if( i!=j && (num[i]&num[j])!=0 )
f[i][j] = f[j][i] = road[i][j] = road[j][i] = 1;
else
f[i][j] = f[j][i] = road[i][j] = road[j][i] = MAX;
int ans = MAX;
for(int k=0;k<nums;k++)
{
for(int i=0;i<nums;i++)
for(int j=0;j<nums;j++)
if(i!=k&&j!=k&&i!=j)
ans = min(ans,road[i][k]+road[k][j]+f[i][j]);
for(int i=0;i<nums;i++)
for(int j=0;j<nums;j++)
if(i!=j) f[i][j] = min(f[i][j],f[i][k]+f[k][j]);
}
if(ans == MAX) cout<<-1;
else cout<<ans;
}
return 0;
}
其他
关于floyd求最小环的一些想法
在floyd本身是去求解最短路的,而环的构成可以看作是i到j的最短路加上k到i的单位距离和k到j的单位距离。