题目大意:给定一张图,求从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!!!!