zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    第五课 按键控制文本
    第四课:怎么去掉Activity的标题和邮件图标-20160705
    第三课:控件的使用及按键响应-20160705
    第二课:Android Studo 各文件作用-20160705
    第一课:如何创建Android Studo 工程-20160705
    JTAG各类接口针脚定义及含义
    c# 定时器的实现
    二进制及十进制文件的读写方法
    c# 检测设备改变
    Vue(四)事件和属性
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/9394008.html
Copyright © 2011-2022 走看看