http://acm.hdu.edu.cn/showproblem.php?pid=3416
题意:给出n个点m条边,边信息分别是两个端点和一个费用,再给出一个起点和一个终点,问从起点到终点的完全不相同的最短路径有多少条。(即走过的边不能在走过了)。
思路:因为是在网络流专题里面,所以一开始以为先用SPFA跑一个最小费用出来,然后再用最小费用最大流(然而是最小费用最大流是满足最大流的前提下再考虑最小费用的,很明显是行不通的)。后来想要保证路径不重复,就跑完一次最短路就删除路径(好像也是行不通)。然后只能看下题解了= =。
从起点到终点跑一次SPFA,再从终点到起点跑一次SPFA,这里第一次SPFA跑出来的距离数组是d[0],第二次跑出来的是d[1],如果d[0][u] + w(u, v) + d[1][v] == d[0][T],那么这条w(u,v)边一定是最短路上的边。这里说说我对这个定理的看法:d[0][u]是从起点到u点的最短距离,而d[1][v]是从v到终点的最短距离,那么如果加上这条边刚好等于从起点到终点的最短距离,那么这条边就必定是最短路的边,嗯。好像很明显。然后将这些必定在最短路上的边建起网络,容量是1,跑一遍从起点到终点的最大流,就是最终答案了。这样就符合最大流的思想了。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 using namespace std; 7 #define N 1010 8 #define M 200010 9 #define INF 0x3f3f3f3f 10 struct Edge { 11 int v, cap, nxt; 12 Edge () {} 13 Edge (int v, int nxt, int cap) : v(v), nxt(nxt), cap(cap) {} 14 } edge[M], e[M]; 15 int cur[N], pre[N], gap[N], dis[N], d[3][N], vis[N], head[N], h[N], uu[M], vv[M], ww[M], tot, tt, S, T, n, m; 16 17 void Add(int u, int v, int cap, int tag) { 18 if(tag == 1) { e[tt] = Edge(v, h[u], cap); h[u] = tt++; } 19 else { edge[tot] = Edge(v, head[u], cap); head[u] = tot++; edge[tot] = Edge(u, head[v], 0); head[v] = tot++; } 20 } 21 22 void SPFA(int st, int ed, int id) { 23 for(int i = 0; i <= n; i++) d[id][i] = INF; 24 memset(vis, 0, sizeof(vis)); 25 queue<int> que; que.push(st); 26 vis[st] = 1; d[id][st] = 0; 27 while(!que.empty()) { 28 int u = que.front(); que.pop(); vis[u] = 0; 29 for(int i = h[u]; ~i; i = e[i].nxt) { 30 int v = e[i].v, w = e[i].cap; 31 if(d[id][v] > d[id][u] + w) { 32 d[id][v] = d[id][u] + w; 33 if(vis[v]) continue; 34 que.push(v); vis[v] = 1; 35 } 36 } 37 } 38 } 39 40 void BFS() { 41 memset(dis, INF, sizeof(dis)); 42 memset(gap, 0, sizeof(gap)); 43 queue<int> que; que.push(T); 44 dis[T] = 0; gap[0]++; 45 while(!que.empty()) { 46 int u = que.front(); que.pop(); 47 for(int i = head[u]; ~i; i = edge[i].nxt) { 48 int v = edge[i].v; 49 if(dis[v] != INF) continue; 50 dis[v] = dis[u] + 1; 51 gap[dis[v]]++; 52 que.push(v); 53 } 54 } 55 } 56 57 int ISAP(int n) { 58 BFS(); 59 memcpy(cur, head, sizeof(cur)); 60 int u = pre[S] = S, ans = 0, flow, i, index; 61 while(dis[S] < n) { 62 if(u == T) { 63 flow = INF; 64 for(i = S; i != T; i = edge[cur[i]].v) 65 if(flow > edge[cur[i]].cap) flow = edge[cur[i]].cap, index = i; 66 for(i = S; i != T; i = edge[cur[i]].v) 67 edge[cur[i]].cap -= flow, edge[cur[i]^1].cap += flow; 68 u = index; ans += flow; 69 } 70 for(i = cur[u]; ~i; i = edge[i].nxt) if(edge[i].cap > 0 && dis[edge[i].v] + 1 == dis[u]) break; 71 if(~i) { cur[u] = i; pre[edge[i].v] = u; u = edge[i].v; } 72 else { 73 if(--gap[dis[u]] == 0) break; 74 int md = n + 1; 75 for(i = head[u]; ~i; i = edge[i].nxt) 76 if(dis[edge[i].v] < md && edge[i].cap > 0) md = dis[edge[i].v], cur[u] = i; 77 gap[dis[u] = md + 1]++; 78 u = pre[u]; 79 } 80 } 81 return ans; 82 } 83 84 int main() { 85 int t; 86 scanf("%d", &t); 87 while(t--) { 88 scanf("%d%d", &n, &m); 89 int edgenum = 0; 90 for(int i = 1; i <= m; i++) { 91 int u, v, w; 92 scanf("%d%d%d", &u, &v, &w); 93 //if(u == v) continue; 94 edgenum++; uu[edgenum] = u; vv[edgenum] = v; ww[edgenum] = w; 95 } 96 scanf("%d%d", &S, &T); 97 memset(h, -1, sizeof(h)); tt = 0; 98 for(int i = 1; i <= edgenum; i++) Add(uu[i], vv[i], ww[i], 1); 99 SPFA(S, T, 0); 100 memset(h, -1, sizeof(h)); tt = 0; 101 for(int i = 1; i <= edgenum; i++) Add(vv[i], uu[i], ww[i], 1); 102 SPFA(T, S, 1); 103 memset(head, -1, sizeof(head)); tot = 0; 104 for(int i = 1; i <= edgenum; i++) 105 if(d[0][uu[i]] + d[1][vv[i]] + ww[i] == d[0][T]) Add(uu[i], vv[i], 1, 2); // 容量设成1.而不是ww 106 int ans = ISAP(n + 1); 107 printf("%d ", ans); 108 } 109 return 0; 110 }