1. 程式人生 > >hdu6331 /// Floyd+分塊DP

hdu6331 /// Floyd+分塊DP

eof 單向 display esp none 最小 sed view set

題目大意:

給定單向圖的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

hdu6331 /// Floyd+分塊DP