POJ 3422 最小费用最大流

链接:

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

题解:

关键是如何处理“只能获取一次”的问题,为此可以为每个点创建伪点,由两条有向边相连。原始点到伪点连一条容量为1,权值为负分数的边;原始点到伪点连一条容量为无穷,权值为0的边。前者表示分数只能拿一次,后者表示第二次第三次……可以继续走这个点,但是不拿分数。负权是因为题目要求的是“最大费用”。又因为最多走同一个点K次,所以此处的无穷大取K就行了。

代码:

  1 #include <map>
  2 #include <set>
  3 #include <cmath>
  4 #include <queue>
  5 #include <stack>
  6 #include <cstdio>
  7 #include <string>
  8 #include <vector>
  9 #include <cstdlib>
 10 #include <cstring>
 11 #include <sstream>
 12 #include <iostream>
 13 #include <algorithm>
 14 #include <functional>
 15 using namespace std;
 16 #define rep(i,a,n) for (int i=a;i<n;i++)
 17 #define per(i,a,n) for (int i=n-1;i>=a;i--)
 18 #define pb push_back
 19 #define mp make_pair
 20 #define all(x) (x).begin(),(x).end()
 21 #define SZ(x) ((int)(x).size())
 22 typedef vector<int> VI;
 23 typedef long long ll;
 24 typedef pair<int, int> PII;
 25 const ll mod = 1e9 + 7;
 26 const int inf = 0x3f3f3f3f;
 27 const double eps = 1e-10;
 28 const double pi = acos(-1.0);
 29 // head
 30 
 31 struct edge { int to, cap, cost, rev; };
 32 const int MAX_V = 2e4 + 7;
 33 int V;
 34 vector<edge> G[MAX_V];
 35 int h[MAX_V];
 36 int dist[MAX_V];
 37 int prevv[MAX_V], preve[MAX_V];
 38 
 39 void add_edge(int from, int to, int cap, int cost) {
 40     G[from].pb(edge{ to,cap,cost,(int)G[to].size() });
 41     G[to].pb(edge{ from,0,-cost,(int)G[from].size() - 1 });
 42 }
 43 
 44 int min_cost_flow(int s, int t, int f){
 45     int res = 0;
 46     memset(h, 0, sizeof(h));
 47     while (f > 0) {
 48         priority_queue<PII, vector<PII>, greater<PII> > que;
 49         memset(dist, 0x3f, sizeof(dist));
 50         dist[s] = 0;
 51         que.push(mp(s, 0));
 52         while (!que.empty()) {
 53             PII p = que.top(); que.pop();
 54             int v = p.second;
 55             rep(i, 0, G[v].size()) {
 56                 edge &e = G[v][i];
 57                 if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
 58                     dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
 59                     prevv[e.to] = v;
 60                     preve[e.to] = i;
 61                     que.push(mp(dist[e.to], e.to));
 62                 }
 63             }
 64         }
 65         if (dist[t] == inf) return -1;
 66         rep(v, 0, V) h[v] += dist[v];
 67         int d = f;
 68         for (int v = t; v != s; v = prevv[v]) d = min(d, G[prevv[v]][preve[v]].cap);
 69         f -= d;
 70         res += d*h[t];
 71         for (int v = t; v != s; v = prevv[v]) {
 72             edge &e = G[prevv[v]][preve[v]];
 73             e.cap -= d;
 74             G[v][e.rev].cap += d;
 75         }
 76     }
 77     return res;
 78 }
 79 
 80 int n, k;
 81 
 82 int pos(int i, int j){
 83     return 2 * (i * n + j);
 84 }
 85 
 86 int main() {
 87     cin >> n >> k;
 88     V = n*n * 2;
 89     rep(i, 0, n) rep(j, 0, n) {
 90         int a;
 91         cin >> a;
 92         int cur = pos(i, j);
 93         add_edge(cur, cur + 1, 1, -a);
 94         add_edge(cur, cur + 1, inf, 0);
 95         if (i < n - 1) add_edge(cur + 1, pos(i + 1, j), inf, 0);
 96         if (j < n - 1) add_edge(cur + 1, pos(i, j + 1), inf, 0);
 97     }
 98     cout << - min_cost_flow(0, V - 1, k) << endl;
 99     return 0;
100 }

 

posted @ 2017-04-04 19:48  Flowersea  阅读(196)  评论(3编辑  收藏  举报