zoukankan      html  css  js  c++  java
  • POJ 2175:Evacuation Plan(费用流消圈算法)***

    http://poj.org/problem?id=2175

    题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给出一个方案,问该方案是否是让所有人到防空洞避难的花费时间最少的方案,如果不是,输出一个最佳方案。

    思路:一开始直接用最小费用最大流,超时了。学习了一下消圈算法。

    如果不考虑得到最小费用,只需要考虑当前是否最小费用的话,那么是可以用消圈算法来解决的。

    结论:当没有负圈的时候,当前的费用是最小的。

    因此,构图的时候,根据给出的方案构造出残余网络,然后直接跑一遍SPFA,如果出现负圈,说明当前的答案不是最优的(因为反向边是-cost,可以得到更小的费用,因此是负圈)。

    考虑构造新的方案:对于该负圈,记录起路径,然后遍历,因为图存的是正向边的流量,所以如果正向边出现在负圈里,需要加上,代表跑这条边更优,反向边则减去。

    学习地址

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <cstring>
      5 #include <string>
      6 #include <cmath>
      7 #include <queue>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <stack>
     12 using namespace std;
     13 #define INF 0x3f3f3f3f
     14 #define N 210
     15 typedef long long LL;
     16 struct Edge {
     17     int u, v, nxt, cap, cost;
     18 } edge[N*N];
     19 int head[N], tot, pre[N], dis[N], vis[N], inq[N], x[N], y[N], b[N], p[N], q[N], c[N], mp[N][N], S, T;
     20 
     21 void Add(int u, int v, int cap, int now, int cost) {
     22     edge[tot] = (Edge) { u, v, head[u], cap - now, cost }; head[u] = tot++;
     23     edge[tot] = (Edge) { v, u, head[v], now, -cost }; head[v] = tot++;
     24 }
     25 
     26 int cal(int x1, int y1, int x2, int y2) { return abs(x2 - x1) + abs(y2 - y1) + 1; }
     27 
     28 int SPFA(int S, int n) {
     29     queue<int> que;
     30     que.push(S);
     31     memset(dis, INF, sizeof(dis));
     32     memset(vis, 0, sizeof(vis));
     33     memset(inq, 0, sizeof(inq));
     34     dis[S] = 0; vis[S] = 1; pre[S] = S;
     35     while(!que.empty()) {
     36         int u = que.front(); que.pop();
     37         vis[u] = 0;
     38         for(int i = head[u]; ~i; i = edge[i].nxt) {
     39             int v = edge[i].v, cost = edge[i].cost, cap = edge[i].cap;
     40             if(dis[v] > dis[u] + cost && cap > 0) {
     41                 dis[v] = dis[u] + cost; pre[v] = u;
     42                 if(!vis[v]) {
     43                     vis[v] = 1, que.push(v);
     44                     if(++inq[v] > n) return v;
     45                 }
     46             }
     47         }
     48     }
     49     return 0;
     50 }
     51 
     52 bool inside(int L, int R, int now) { if(L <= now && now <= R) return true; return false; }
     53 
     54 int main() {
     55     int n, m;
     56     while(~scanf("%d%d", &n, &m)) {
     57         S = 0, T = n + m + 1; int res = 0, ans;
     58         memset(head, -1, sizeof(head)), tot = 0;
     59         memset(dis, 0, sizeof(dis));
     60         for(int i = 1; i <= n; i++) scanf("%d%d%d", &x[i], &y[i], &b[i]);
     61         for(int i = 1; i <= m; i++) scanf("%d%d%d", &p[i], &q[i], &c[i]);
     62         for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) {
     63             scanf("%d", &mp[i][j]);
     64             int d = cal(x[i], y[i], p[j], q[j]);
     65             Add(i, j + n, INF, mp[i][j], d);
     66             res += d * mp[i][j]; dis[j] += mp[i][j];
     67         }
     68         for(int i = 1; i <= n; i++) Add(S, i, b[i], 0, 0);
     69         for(int i = 1; i <= m; i++) Add(i + n, T, c[i], dis[i], 0);
     70         ans = SPFA(S, T);
     71         if(!ans) puts("OPTIMAL");
     72         else {
     73             memset(vis, 0, sizeof(vis));
     74             while(!vis[ans]) { vis[ans] = 1; ans = pre[ans]; }
     75             int tmp = ans;
     76             do { // 图存的是正向边的流量,因此如果正向边出现在负圈里,需要加上,代表跑这条边更优,反向边减去
     77                 if(inside(1, n, pre[tmp]) && inside(n + 1, n + m, tmp)) mp[pre[tmp]][tmp-n]++;
     78                 if(inside(1, n, tmp) && inside(n + 1, n + m, pre[tmp])) mp[tmp][pre[tmp]-n]--;
     79                 tmp = pre[tmp];
     80             } while(tmp != ans);
     81             puts("SUBOPTIMAL");
     82             for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++)
     83                 printf("%d%c", mp[i][j], j == m ? '
    ' : ' ');
     84         }
     85     }
     86     return 0;
     87 }
     88 
     89 /*
     90 3 4
     91 -3 3 5
     92 -2 -2 6
     93 2 2 5
     94 -1 1 3
     95 1 1 4
     96 -2 -2 7
     97 0 -1 3
     98 3 1 1 0
     99 0 0 6 0
    100 0 3 0 2
    101 */
  • 相关阅读:
    kill tomcat with netstat
    windows cmd命令显示UTF8设置
    rtx没有振动功能
    手动加载rvm
    RESTful Java client with Apache HttpClient
    Set Up Git on windows also use github
    lcs.py 最长公共子串算法
    如何:对代理使用 IP 切换
    这个博客站点不错
    a case study
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6750395.html
Copyright © 2011-2022 走看看