B. Shortest Cycle 无向图求最小环

题意:
给定 n 个点,每个点有一个权值a[i],如果a[u]&a[v] != 0,那么就可以在(u,v)之间连一条边,求最后图的最小环(环由几个点构成)

题解:
逻辑运算 & 是二进制下的运算,题目给的每个权值 a[i] 的范围最大是1018,即二进制下最多64位。
如果64位中有某一位的1的出现数大于 2 了,那么很明显,最小环就是3(该位循环)。
换个说法,在最坏的情况下,给出了 n 个数,其中有超过 128 个不为 0 的数,那么答案一定是3(因为当有128个不为0的数时,64位每一位的个数都是2,只要再随便来个不为0的数,都会出现大于2的位数,构成 3 的环)

所以我们只要考虑不为 0 的数的个数小于130的情况就行了,这个时候 n 就很小了,可以用dfs搜索或者用Flyod求最小环。

#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#define ll long long
#define mx 0x3f3f3f3f
using namespace std;
ll way[250][250],dis[250][250],num[250];
ll n,m,ans;
void init()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i!=j&&num[i]&num[j])
                way[i][j]=dis[i][j]=1;
            else
                way[i][j]=dis[i][j]=mx;
        }
    }
}
void floyd()
{
    ans=mx;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
        {
            for(int j=i+1;j<k;j++)
                ans=min(ans,dis[i][j]+way[i][k]+way[k][j]);//接成环
        }

        for(int i=1;i<=n;i++)//求最短路
            for(int j=1;j<=n;j++)
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    }
}
int main()
{
    while(~scanf("%lld",&n))
    {
        ll cnt=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&num[i]);
            if(num[i])
                cnt++;
        }
        if(cnt>130)
            printf("3\n");
        else
        {
            init();
            floyd();
            if(ans==mx)
                printf("-1\n");
            else
                printf("%lld\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/-citywall123/p/11461636.html
今日推荐