hdu6331 /// Floyd+分块DP

题目大意:

给定单向图的n m 为点数和单向边数

接下来m行给定 u v w 为边的起点终点和长度

给定q 为询问个数

接下来q行给定 x y k 求从x到y至少经过k条边的最短路长度

 

https://blog.csdn.net/qkoqhh/article/details/81301910

设 d[ i ][ j ][ k ] 为从i到j走至少k条边的最短路长度

设 f[ i ][ j ][ k ] 为从i到j恰好走k*100条边的最短路长度

那么至少走K条边的话

若 K>=100 有 f[ i ][ j ][ K/100 ] + d[ i ][ j ][ K%100 ]

若 K%100==0 有 f[ i ][ j ][ K/100 ]

若 K<100 有 d[ i ][ j ][ K ]

最小值就是至少走K条边的最短路

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int N=50+5;
const int M=1e4+5;
int n, m;
int d[N][N][150], f[N][N][105];
int main()
{
    int _; scanf("%d",&_);
    while(_--) {
        scanf("%d%d",&n,&m);
        inc(i,1,n)inc(j,1,n) d[i][j][1]=INF; 
        while(m--) {
            int u,v,w; scanf("%d%d%d",&u,&v,&w);
            d[u][v][1]=min(d[u][v][1],w); // 更新至少1条边的答案
        }
        inc(i,1,n)inc(j,1,n) d[i][j][0]=d[i][j][1]; 
// 至少0条边的答案应和至少1条相同
        inc(i,1,n) d[i][i][0]=0;
// 点到本身的距离至少0条边答案肯定为0
        inc(k,2,150) {
            inc(i,1,n)inc(j,1,n) d[i][j][k]=INF;
            inc(p,1,n)inc(i,1,n)inc(j,1,n) // Floyd
                d[i][j][k]=min(d[i][j][k],d[i][p][k-1]+d[p][j][1]);
        }
        inc(i,1,n)inc(j,1,n) f[i][j][1]=d[i][j][100];
// 按100条边(求了150条)分块应该够了
        inc(k,2,100) {
            inc(i,1,n)inc(j,1,n) f[i][j][k]=INF;
            inc(p,1,n)inc(i,1,n)inc(j,1,n) // Floyd
                f[i][j][k]=min(f[i][j][k],f[i][p][k-1]+f[p][j][1]);
        }
        dec(k,149,0)
            inc(i,1,n)inc(j,1,n)
                d[i][j][k]=min(d[i][j][k],d[i][j][k+1]);
// 至少k条边的答案 如果k+1的答案更优 同样可以更新
        int q; scanf("%d",&q);
        while(q--) {
            int u,v,k; scanf("%d%d%d",&u,&v,&k);
            int ans=INF;
            if(k>100) {
                inc(p,1,n)
                ans=min(ans,f[u][p][k/100]+d[p][v][k%100]);
            }
            if(k%100==0) ans=min(ans,f[u][v][k/100]);
            if(k<=100) ans=min(ans,d[u][v][k]);
            if(ans==INF) printf("-1\n");
            else printf("%d\n",ans);
        }
    }

    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/zquzjx/p/10416130.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值