Loading

HDU 3416:Marriage Match IV(最短路+最大流)

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\n", ans);
108     }
109     return 0;
110 }

 

posted @ 2017-01-23 12:44  Shadowdsp  阅读(316)  评论(0编辑  收藏  举报