tnnd,又得翻译英文题面
题意:
有n个数,任意 两个数,第i-th 个数字 和 第 j-th个数字,他们的 & 不为0的话,就会有这么一条无向边 i – j,边权为 1. 现在问,这个图中 最小环的长度是多少。
思路:
第一眼看题: 如果数据小的话,我直接 floyd 找最小环 但是,tnnd, 这个数据太大了
重点:
&… 仔细想下,两个数的 &运算, 如果 有超过三个数 他们的 一个位上 都是1, 那就形成最小环 为 3 了。
a 的范围是 1018,二进制有64位, 先不形成环,每一位上分别形成 2 个1,也就是最多 64×2 个数字。他们不形成环,最多有 64×2 个数。
举个栗子: 0001,0001,0010,0010,0100,0100,1000,1000,
一共4位,当数字出现的个数不大于4×2 的时候,可能不形成环,但是数字出现的个数一旦大于4×2,那就 必然有最小环3. (因为必然有有一位上 有3个1)。
那问题就变得简单了,只要不为0的数字大于128,就必有最小环3。没有超过的话,直接floyd。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+177;
const ll inf=0x3f3f3f3f;
ll mapp[517][517];
ll dis[517][517];
ll a[maxn];
void init(){
for(int i=0;i<=507;i++){
for(int j=0;j<=507;j++){
mapp[i][j]=inf;
dis[i][j]=inf;
}
}
}
int main(){
int n;
scanf("%d",&n);
ll x;
int kk=0;
for(int i=0;i<n;i++){
scanf("%lld",&x);
if(x!=0){
a[kk++]=x;
}
}
if(kk>128){
printf("3\n");
return 0;
}
n=kk;
init();
sort(a,a+n);
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(a[i]&a[j]){
mapp[i+1][j+1]=1;
mapp[j+1][i+1]=1;
dis[i+1][j+1]=1;
dis[j+1][i+1]=1;
}
}
}
ll now=inf;
for(int k=1;k<=n;k++){
for(int i=1;i<k;i++){
for(int j=i+1;j<k;j++){
now=min(dis[i][j]+mapp[j][k]+mapp[k][i],now);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[i][j]>dis[i][k]+dis[k][j]){
dis[i][j]=dis[i][k]+dis[k][j];
}
}
}
}
if(now>=inf){
printf("-1\n");
}else{
printf("%lld\n",now);
}
}