【floyed求最小環】【鴿巢原理】D. Shortest Cycle
阿新 • • 發佈:2022-03-10
【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的單位距離。