题目大意:给定一张图,求从1开始到达m的权值至少需要遍历多少条边

n<=100,果断倍增Floyd

f[temp][i][j]表示经过2^temp条边从i走到j的最大权值

更新时f[temp[i][j]=max{f[temp-1][i][k]+f[temp-1][k][j]}

然后用矩阵g[i][j]记录当前走的权值,初始主对角线为0,其余为-∞

从大到小枚举temp,利用f[temp]和g得到矩阵h

如果h中1到某个点的权值超过了m就跳出 否则将当前temp计入ans 然后将g数组更新为h

最后输出ans+1就是答案 证明略

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n;
long long f[70][110][110],g[110][110],h[110][110],m,ans;
void Initialize()
{
	ans=0;
	memset(f,0xef,sizeof f);
	memset(g,0xef,sizeof g);
}
int main()
{
	int T,i,j,k,temp;
	for(cin>>T;T;T--)
	{
		Initialize();
		cin>>n>>m;
		for(i=1;i<=n;i++)
			for(j=1;j<=n;j++)
			{
				#ifndef ONLINE_JUDGE
					scanf("%I64d",&f[0][i][j]);
				#else
					scanf("%lld",&f[0][i][j]);
				#endif
				if(!f[0][i][j])
					f[0][i][j]=0xefefefefefefefefll;
			}
		try{
			for(temp=1;1ll<<temp<=m;temp++)
				for(k=1;k<=n;k++)
					for(i=1;i<=n;i++)
						for(j=1;j<=n;j++)
						{
							f[temp][i][j]=max(f[temp][i][j],f[temp-1][i][k]+f[temp-1][k][j]);
							if(i==1&&f[temp][i][j]>=m)
								throw(true);
						}
		}
		catch(bool) {}
		for(i=1;i<=n;i++)
			g[i][i]=0;
		while(temp--)
		{
			memset(h,0xef,sizeof h);
			try{
				for(k=1;k<=n;k++)
					for(i=1;i<=n;i++)
						for(j=1;j<=n;j++)
						{
							h[i][j]=max(h[i][j],f[temp][i][k]+g[k][j]);
							if(i==1&&h[i][j]>=m) throw(true);
						}
				memcpy(g,h,sizeof g);ans+=1ll<<temp;
			}
			catch(bool) {}
		}
		cout<<ans+1<<endl;
	}
	return 0;
}
//lld!!!!