BZOJ 2165 大楼 倍增Floyd

来源:互联网 发布:故宫淘宝h5 编辑:程序博客网 时间:2024/05/01 12:07

题目大意:给定一张图,求从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_JUDGEscanf("%I64d",&f[0][i][j]);#elsescanf("%lld",&f[0][i][j]);#endifif(!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!!!!


0 0