链接:
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 }