看了这里 http://blog.csdn.net/acm_cxlove/article/details/8679230的分析之后自己又按照自己的模板写了一遍,算是对spfa又加深了一步认识(以前真是只会用,没想太多)。
又来当一次搬运工,一点点进步。
题意是这样的:A个村庄,B个城堡,共有K次穿越的机会,且不能经过城堡或者穿越距离必须不超过L,否则必须停下来,当然,不能再道路中间停下来。
按照大大的思路是这样做的:对于每出队的一个结点u,均有两种方式继续走下去,一中是使用一次穿越,另一种是不使用。这样对于使用穿越的情况,必须考虑所有满足d[u][v]<=L的点v,然后dp[v][k+1] = min(dp[v][k+1],dp[u][k])转移方程,其中dp[u][k]表示从起点A+B走到u使用k次穿越经过的最小距离;对于不使用穿越的情况就和普通spfa一样转移。
然后怎样判断由一个节点到另一个节点能够满足d[u][v]<=L呢,这中间会涉及到城堡不能穿越,可以求出使用spfa求出(i,j)之间的最短距离,对于j是城堡的时候就不把j入队,这样中间有城堡的两个节点d[i][j]是不能直接穿越的,也就是d[i][j] == inf.
然后下面是我写的代码:
(思路也可以去原po那里看)
1 #include <iostream> 2 #include <cstdio> 3 #include <climits> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cmath> 7 #include <vector> 8 #include <queue> 9 #include <algorithm> 10 #define esp 1e-6 11 #define pb push_back 12 #define in freopen("in.txt", "r", stdin); 13 #define out freopen("out.txt", "w", stdout); 14 #define print(a) printf("%d ",(a)); 15 #define bug puts("********))))))"); 16 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 17 #define inf 0x3f3f3f3f 18 using namespace std; 19 typedef long long LL; 20 typedef vector<int> VI; 21 typedef vector<int>:: iterator IT; 22 #define N 2000 23 #define INF 200000 24 struct EDGE 25 { 26 int i, c; 27 EDGE *ani,*next; 28 } *Edge[N], E[INF]; 29 int d[N][N], inq[N], dp[N][20]; 30 int cnt, A, B, M, L, K; 31 void add(int i, int j, int c, EDGE &e1, EDGE &e2) 32 { 33 e1.i = j, e1.c = c, e1.ani = &e2, e1.next = Edge[i], Edge[i] = &e1; 34 e2.i = i, e2.c = c, e2.ani = &e1, e2.next = Edge[j], Edge[j] = &e2; 35 cnt += 2; 36 } 37 void init(void) 38 { 39 cnt = 0; 40 memset(Edge, 0, sizeof(Edge)); 41 // memset(d, 0x0f, sizeof(d)); 42 } 43 void preprocess(void) 44 { 45 memset(d, 0x3f, sizeof(d)); 46 for(int i = 1; i <= A + B; i++) 47 { 48 queue<int> q; 49 memset(inq, 0, sizeof(inq)); 50 inq[i] = 1; 51 d[i][i] = 0; 52 q.push(i); 53 while(!q.empty()) 54 { 55 int u = q.front(); 56 int v; 57 q.pop(); 58 inq[u] = 0; 59 for(EDGE * p = Edge[u]; p; p = p->next) 60 if(d[i][v = p->i] > d[i][u] + p->c) 61 { 62 if(d[i][v] = d[i][u] + p->c, v <= A && !inq[v]) 63 inq[v] = 1, q.push(v); 64 } 65 } 66 } 67 } 68 void spfa(int s, int end) 69 { 70 memset(dp, 0x3f, sizeof(dp)); 71 memset(inq, 0, sizeof(inq)); 72 queue<int> q; 73 inq[s] = 1; 74 dp[s][0] = 0; 75 q.push(s); 76 while(!q.empty()) 77 { 78 int u = q.front(), v; 79 q.pop(); 80 inq[u] = 0; 81 for(EDGE *p = Edge[u]; p; p = p->next) 82 for(int k = 0; k <= K; k++) 83 if(dp[u][k] < inf) 84 { 85 if(dp[v = p->i][k] > dp[u][k] + p->c) 86 if(dp[v][k] = dp[u][k] + p->c, !inq[v]) 87 inq[v] = 1, q.push(v); 88 if(k - K) 89 { 90 for(v = 1; v <= A + B; v++) 91 // if(dp[u][k] < inf) 92 if(d[u][v] <= L && dp[u][k] < dp[v][k+1]) 93 if(dp[v][k+1] = dp[u][k], !inq[v]) 94 inq[v] = 1, q.push(v); 95 } 96 } 97 } 98 } 99 int main(void) 100 { 101 102 int T; 103 for(int t = scanf("%d", &T); t <= T; t++) 104 { 105 init(); 106 scanf("%d%d%d%d%d", &A, &B, &M, &L, &K); 107 for(int i = 1; i <= M; i++) 108 { 109 int u, v, w; 110 scanf("%d%d%d", &u, &v, &w); 111 add(u, v, w, E[cnt], E[cnt + 1]); 112 } 113 preprocess(); 114 spfa(A+B, 1); 115 int ans = inf; 116 for(int k = 0; k <= K; k++) 117 ans = min(dp[1][k], ans); 118 printf("%d ", ans); 119 } 120 return 0; 121 }