无向图最小环——Floyd解法

题目链接
简单讲一下题意:
给n(<=1e5)个数,数字范围(1e18)任意两个数字之间如果经过与运算以后不为0则可以判为两点相连,给出最小环大小,如果没有则输出-1;
第一步将1e5变小,可以发现只要二进制的任意一位上面出现过3个乃至以上的1则只需输出3,大致算一下那么只有100个数字左右了可以跑Floyd了!!
由Floyd算法可以知道,在它运行到以k做中间节点时,前面经过所有点都比k小的节点之间的最短路径其实已经确定了。因为在k做中间节点时他的最大节点必须大于等于k。
因此每一次枚举一个中间节点我们都可以知道前面所产生的比k小的所有的最短路径。
而一个环(p->i->j->p)的长度为dis[i][j]+a[p][i]+a[j][p];我们每一次枚举dis[i][j]的长度再加上原本图上的两条边找到最小值就行了

#include 
#include 
#include 
#include 
using namespace std;
const int N = 1e5 + 5;
int n, cnt = 0,dis[200][200], p[200][200];
long long ans = N,a[N], b[N];
void floyd(void)
{
	for (int i = 1; i <= cnt; i++)//一定经过i点
	{
		for (int j = 1; j < i; j++)//枚举比i小的一个点
		{
			for (int k = j+1; k < i; k++)//
			{
				if(k!=j)
				ans = min((long long)dis[j][k] + p[k][i] + p[i][j], ans);//0x3f3f3f3f*3越int了
				//cout << ans< 0; j--)
		{
			if ((a[i] >> j)&1) v[j]++;
		}
	}
	for (int i = 1; i <= 62; i++)
	{
		if (v[i] > 2)
		{
			puts("3");
			return 0;
		}
	}
	for (int i = 1; i <= n; i++) if (a[i]) b[++cnt] = a[i];
	for (int i = 1; i <= cnt; i++)
	{
		for (int j = 1; j <= cnt; j++)
		{
			if (b[i] & b[j]) dis[i][j] = 1, p[i][j] = 1;
		}
	}
	//cout << ans << endl;
	floyd();
	//printf_s("%lld\n", ans);
	if (ans == N) ans = -1;
	cout << ans;
}

你可能感兴趣的:(图论)