hdu6331 Problem M. Walking Plan

Posted yzxverygood

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu6331 Problem M. Walking Plan相关的知识,希望对你有一定的参考价值。

传送门

题目大意

给你一个n点m条边的有向图,q次询问,给定s,t,k,求由s到t至少经过k条边的最短路。

分析

我们设dp[i][j][k]为从i到j至少经过k条边的最短路,sp[i][j]意为从i到j只经过一条边的最短路,于是我们可以得到转移方程式:dp[i][k]=Min{dp[i][m][k-1]+sp[m][j]}。但是我们发现这个样复杂度并不行,于是我们考虑分块,定每一个块的大小为100,对于小于等于100的所有k我们使用上面的dp式子暴力预处理,在这之后我们将按以上方式求出的k=100时的值作为新的sp来更新所有为100的倍数的情况,注意由于题目要求是至少经过k条边而不是正好经过k条边,所以这个地方我们需要使用两点间最短距离更新一下之前求出的数组(具体实现见代码)。在有了这些预处理之后我们将给定的k分块,使得q=k/100,r=k%100,所以我们只需枚举一个v使得s到v经过r条边的最短路+v到t经过100q条边的最短路最小即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int inf = 0x3f3f3f3f;
int n,m,g[60][60],d[60][60],f[60][60],a[101][60][60],b[101][60][60],use[60][60];
inline void mul(int a[][60],int b[][60],int c[][60]){
      int i,j,k;
      memset(use,0x3f,sizeof(use));
      for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
          for(k=1;k<=n;k++)
            use[i][j]=min(use[i][j],a[i][k]+b[k][j]);
      for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
          c[i][j]=use[i][j];
}
int main(){
      int i,j,k,t;
      scanf("%d",&t);
      while(t--){
          memset(g,0x3f,sizeof(g));
          scanf("%d%d",&n,&m);
          for(i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
          g[x][y]=min(g[x][y],z); 
          }
          for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
              a[0][i][j]=b[0][i][j]=(i==j?0:inf);
          for(i=1;i<=100;i++)
            mul(a[i-1],g,a[i]);
          for(i=1;i<=100;i++)
            mul(b[i-1],a[100],b[i]);
          for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
              d[i][j]=(i==j?0:g[i][j]);
          for(k=1;k<=n;k++)
            for(i=1;i<=n;i++)
              for(j=1;j<=n;j++)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
          for(int _=0;_<=100;_++){
            memset(f,0x3f,sizeof(f));
            for(i=1;i<=n;i++)
              for(j=1;j<=n;j++)
                for(k=1;k<=n;k++)
                  f[i][j]=min(f[i][j],b[_][i][k]+d[k][j]);
            for(i=1;i<=n;i++)
              for(j=1;j<=n;j++)
                b[_][i][j]=f[i][j];
          }
          int q;
          scanf("%d",&q);
          for(i=1;i<=q;i++){
            int s,t,K;
            scanf("%d%d%d",&s,&t,&K);
            int s1=K%100,s2=K/100;
            int ans=inf;
            for(j=1;j<=n;j++)
              ans=min(ans,a[s1][s][j]+b[s2][j][t]);
            if(ans<inf)printf("%d
",ans);
              else puts("-1");
          }
      }
      return 0;
}

以上是关于hdu6331 Problem M. Walking Plan的主要内容,如果未能解决你的问题,请参考以下文章

M - Walking Plan HDU - 6331

[2019HDU多校第一场][HDU 6590][M. Code]

ACM-ICPC 2017 沈阳赛区现场赛 M. Wandering Robots && HDU 6229

2018-2019 ACM-ICPC南京 M. Mediocre String Problem(SAM+PAM)

2018 HDU多校第三场赛后补题

hdu1016 Prime Ring Problem