Codeforces1205B Shortest Cycle 【Flyod求最小环】


传送门:Codeforces1205B


B. Shortest Cycle
time limit per test:1 second
memory limit per test:256 megabytes
input:standard input
output:standard output

You are given n integer numbers a1,a2,…,an. Consider graph on n nodes, in which nodes i, j (i≠j) are connected if and only if, ai AND aj≠0, where AND denotes the bitwise AND operation.

Find the length of the shortest cycle in this graph or determine that it doesn’t have cycles at all.

Input
The first line contains one integer n (1≤n≤105) — number of numbers.

The second line contains n integer numbers a1,a2,…,an (0≤ai≤1018).

Output
If the graph doesn’t have any cycles, output −1. Else output the length of the shortest cycle.

Examples
input
4
3 6 28 9
output
4
input
5
5 12 9 16 48
output
3
input
4
1 2 4 8
output
-1

Note
In the first example, the shortest cycle is (9,3,6,28).

In the second example, the shortest cycle is (5,12,9).

The graph has no cycles in the third example.



题意:
给定 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求最小环。

我之前并不会Flyod求最小环,所以去学了一下。

Flyod求最小环:
令 e(u,v) 表示 u,v之间的连边,min(u,v)表示去掉u,v之间连边后,u,v之间最短路径;
所以最小环就是 e(u,v)+min(u,v)



AC代码:

#include
#include
#include
#include
#include
#include
#define ll long long
#define inf 1e8+10
using namespace std;
const int N=110000;
int n;
ll a[N];
int dis[250][250],mp[250][250];
void build()
{
  for(int i=1;i<=n;i++)
  {
    for(int j=1;j<=n;j++)
    {
      if((a[i]&a[j])&&i!=j)
        dis[i][j]=mp[i][j]=1;
      else
        dis[i][j]=mp[i][j]=inf;
    }
  }
}
int flyod()
{
  int res=inf;
  for(int k=1;k<=n;k++)
  {
    for(int i=1;i<k;i++)
    {
      for(int j=i+1;j<k;j++)
        res=min(res,dis[i][j]+mp[i][k]+mp[k][j]);//假设k再i,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]);//去掉连边后的最短路
    }
  }
  return res;
}

int main()
{
  ll x;
  int cnt=0;//不为0的数的个数
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
  {
    scanf("%I64d",&x);
    if(x!=0) a[++cnt]=x;
  }
  n=cnt;
  if(n>=130) printf("3\n");
  else
  {
    build();
    int res=flyod();
    if(res>n) printf("-1\n");//最小环大于n,即不可构造
    else printf("%d\n",res);
  }
  return 0;
}

你可能感兴趣的:(最短路)