Codeforces 1205 B-Shortest Cycle 【最小环】

题目来源:https://codeforces.com/problemset/problem/1205/B
在这里插入图片描述
★这题真的非常可惜,我就差那么一点点就做出来了,可能还是自己太蒟蒻了…


题意:

有n个数,把他们看作是n个点。如果数a、b有 a&b不等于0,那么数a和数b所对应的点就可以相连。问 这n个数中,最短的环的长度是多少,没有就输出-1 。(长度一定要大于2)


思路:

首先我想,如果两个数a和b都是奇数,那么他们 一定相连,因为他们有共同的1。
接着 如果有 3个奇数,那不就可以成环了吗,而且不论n是多少,只要有3个奇数,最小环的长度一定是3
这还是远远不够的,上面思维 一直局限在最右边的二进制位
再仔细一想,不管二进制位的哪一个位上出现过3次1,那么不论n是多少,最小环的长度一定是3
数的范围是1e18,就是差不多有60个二进制位,num数组统计一下就好(60 x n)次循环基本搞定

上面是 特判,普通情况呢?
如果二进制位出现1的次数不能超过3,那意味着 二进制位数出现1次数为2 的才是我们需要的数(如果1出现一次绝对不行,自己可以想想) 满足条件的数的个数仅仅只有【数学排列组合,60个里面选2个】(60 x 59 / 2)约2000种? 其实不然,深入思考发现忽略了这个限制条件【二进制位出现1的次数为2】,所以 差不多只有60种的亚子?反正不超过200,已经有前人为你铺路了
然后问题就转化成了,有不超过200个数,问他们的最小环的长度是多少 这相当于模板题了吧~


一些废话:

这题是 Codeforces Round #580 (Div. 2) 的D题,当时只有500多个人写出来了,我就已经把下面的代码写出了99.9%,然后一直WA。比赛结束后第二天debug,发现 LL tmp=1ll<<j; 这个地方的1 没有加ll,然后交了一发AC了。算了,吃一堑长一智啊,我不过是运气好罢了~


代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<deque>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e5+5;
const int sz=1<<6;
const int inf=2e9;
const int mod=1e9+7;
const double pi=acos(-1);
typedef long long LL;
LL n,m;
LL f[maxn],g[maxn];
LL dis[200][200],mp[200][200];
int num[63],flag[maxn];
template<class T>
inline void read(T &x)
{
    char c;x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    T res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
int main()
{
    read(n);
    int cnt=0;
    memset(num,0,sizeof num);
    for(int i=1;i<=n;i++){
        read(f[i]);
        flag[i]=0;
        for(int j=0;j<=62;j++){
            LL tmp=1ll<<j;
//            cout<<tmp<<endl;
            if(tmp&f[i]){
                num[j]++;            //数位j出现1的个数++
                flag[i]++;          //第i个数 的二进制数位1的个数++    
            }
        }
    }
//    for(int i=0;i<=60;i++) cout<<i<<' '<<num[i]<<endl;
    for(int i=0;i<=60;i++){                        //特判
        if(num[i]>=3) {cnt=1; break;}
    }
    if(cnt){cout<<"3\n"; return 0;}
    cnt=0;
    for(int i=1;i<=n;i++){                                           //让二进制数位出现1的次数为2的加入
        if(flag[i]>=2){            // ==应该也可以
            g[++cnt]=f[i];
        }
    }
    for(int i=1;i<=cnt;i++){                                //初始化两点间距离
        for(int j=1;j<=cnt;j++){ 
            dis[i][j]=1e9;
            mp[i][j]=1e9;
            if(i!=j){
                if(g[i]&g[j]){                     
//                    cout<<i<<' '<<j<<endl;
                    dis[i][j]=1; mp[i][j]=1;
                }
            }
        }
    }
    LL ans=1e9;
    for(int k=1;k<=cnt;k++){                                    //floyed跑最小环
            for(int i=1;i<k;i++)
                for(int j=i+1;j<k;j++)
                     ans = min(ans,dis[i][j]+mp[i][k]+mp[k][j]);
            for(int i=1;i<=cnt;i++)
                for(int j=1;j<=cnt;j++)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
    if(ans==1e9) ans=-1;
    cout<<ans<<endl;
    return 0;
}

发布了71 篇原创文章 · 获赞 89 · 访问量 8553

猜你喜欢

转载自blog.csdn.net/weixin_43890662/article/details/99712999