• bzoj2165 -- 倍增floyd


    题意:给定一张有向图,求图中从1开始长度>=m且边数最少的路径经过的边数。

    考虑倍增floyd。

    令f[p][i][j]表示经过2p条边从i到j的最大长度。

    那么f[p][i][j]=max{f[p-1][i][k]+f[p-1][k][j]}

    令g[i][j]表示当前答案从i到j的最大长度。

    求答案时从大到小枚举每个二进制位,更新g,若不存在从1开始长度>=m的路径,这一位就是1。

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 #define INF (1ll<<62)
     7 #define N 110
     8 #define M 70
     9 #define ll long long
    10 ll m,f[M][N][N],A[N][N],t[N][N],Ans;
    11 int i,j,k,n,p,T;
    12 inline ll Max(ll x,ll y){return x<y?y:x;}
    13 inline void Init(){
    14     memset(f,0xef,sizeof(f));
    15     memset(A,0xef,sizeof(A));
    16     Ans=0;
    17 }
    18 int main(){
    19     scanf("%d",&T);
    20     while(T--){
    21         scanf("%d%lld",&n,&m);
    22         Init();
    23         for(i=1;i<=n;i++)
    24         for(j=1;j<=n;j++){
    25             scanf("%lld",&f[0][i][j]);
    26             if(f[0][i][j]==0)f[0][i][j]=-INF;
    27         }
    28         for(p=1;1ll<<p<=m;p++){
    29             for(k=1;k<=n;k++){
    30                 for(i=1;i<=n;i++){
    31                     for(j=1;j<=n;j++){
    32                         f[p][i][j]=Max(f[p][i][j],f[p-1][i][k]+f[p-1][k][j]);
    33                         if(i==1&&f[p][i][j]>=m)break;
    34                     }
    35                     if(j<=n)break;
    36                 }
    37                 if(i<=n)break;
    38             }
    39             if(k<=n)break;
    40         }
    41         for(i=1;i<=n;i++)A[i][i]=0;
    42         while(p--){
    43             memset(t,0xef,sizeof(t));
    44             for(k=1;k<=n;k++){
    45                 for(i=1;i<=n;i++){
    46                     for(j=1;j<=n;j++){
    47                         t[i][j]=Max(t[i][j],f[p][i][k]+A[k][j]);
    48                         if(i==1&&t[i][j]>=m)break;
    49                     }
    50                     if(j<=n)break;
    51                 }
    52                 if(i<=n)break;
    53             }
    54             if(k>n){
    55                 memcpy(A,t,sizeof(A));
    56                 Ans+=1ll<<p;
    57             }
    58         }
    59         printf("%lld
    ",Ans+1);
    60     }
    61     return 0;
    62 }
    bzoj2165
  • 相关阅读:
    【线段树合并】联通分量计数
    莫队算法
    Ubuntu实用软件安装[转]
    装系统·折腾记
    Qt环境配置 + Qt使用教程
    Google题解
    隐含马尔科夫模型
    Pythonの坑
    C++11并发编程个人小结
    微软2017年预科生计划在线编程笔试
  • 原文地址:https://www.cnblogs.com/gjghfd/p/6829727.html
Copyright © 2020-2023  润新知