• 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
    ", ans);
    108     }
    109     return 0;
    110 }
  • 相关阅读:
    iOS 中Block以及Blocks的使用,闭包方法调用
    iOS 网络监听、判断
    微信摇一摇实现原理,视图展示
    iOS cocos2d安装以及问题解决
    iOS cocos2d游戏引擎的了解之一
    Leetcode-Valid Sudoku
    Leetcode-Count and Say
    Leetcode-Length of Last Word
    Leetcode-Merge Two Sorted Lists
    Leetcode-Add Binary
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6343834.html
Copyright © 2020-2023  润新知