题目大意:求恰好走k步从S到T的最短路。
思路:设f[p][i][j]为从i到j恰好走2^p步的最短路,DP方程十分简单:f[p][i][j] = min(f[p][i][j],f[p - 1][i][k] + f[p - 1][k][j]);
对总步数T进行二进制拆分,在T有1的位置上,假如这个位置为p,那么就用f[p][][]来更新答案g[][],最后得到的g[][]就是答案矩阵。
注意要离散化一下。。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 210 using namespace std; #define min(a,b) ((a) < (b) ? (a):(b)) #define max(a,b) ((a) > (b) ? (a):(b)) struct Complex{ int x,y,len; void Read() { scanf("%d%d%d",&len,&x,&y); } }edge[MAX]; pair<int,int *> xx[1010]; int cnt,t; int T,edges,points,start,end; int f[20][MAX][MAX],g[MAX][MAX],h[MAX][MAX]; int main() { cin >> T >> edges >> start >> end; memset(g,0x3f,sizeof(g)); memset(f,0x3f,sizeof(f)); for(int i = 1; i <= edges; ++i) { edge[i].Read(); xx[++cnt].first = edge[i].x,xx[cnt].second = &edge[i].x; xx[++cnt].first = edge[i].y,xx[cnt].second = &edge[i].y; } xx[++cnt].first = start,xx[cnt].second = &start; xx[++cnt].first = end,xx[cnt].second = &end; sort(xx + 1,xx + cnt + 1); for(int i = 1; i <= cnt; ++i) { if(i == 1 || xx[i].first != xx[i - 1].first) ++t; *xx[i].second = t; } for(int i = 1; i <= edges; ++i) f[0][edge[i].x][edge[i].y] = f[0][edge[i].y][edge[i].x] = min(f[0][edge[i].x][edge[i].y],edge[i].len); points = t; for(int i = 1; i <= points; ++i) g[i][i] = 0; int p = 0; while(T) { if(T&1) { memset(h,0x3f,sizeof(h)); for(int k = 1; k <= points; ++k) for(int i = 1; i <= points; ++i) for(int j = 1; j <= points; ++j) h[i][j] = min(h[i][j],g[i][k] + f[p][k][j]); memcpy(g,h,sizeof(g)); } T >>= 1; ++p; for(int k = 1; k <= points; ++k) for(int i = 1; i <= points; ++i) for(int j = 1; j <= points; ++j) f[p][i][j] = min(f[p][i][j],f[p - 1][i][k] + f[p - 1][k][j]); } cout << g[start][end] << endl; return 0; }