CF-1206D-D. Shortest Cycle

在这

在这里插入图片描述
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);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值