Codeforces 730I:Olympiad in Programming and Sports(最小费用流)

http://codeforces.com/problemset/problem/730/I

题意:有n个人参加两种比赛,其中每个人有两个参加比赛的属性,如果参加了其中的一个比赛,那么不能参加另一个比赛,每种比赛有一个参加的限制人数,求让两种比赛的属性值最大的方案。

思路:如果往网络流方面想,就挺容易想到最小费用流的。

学习了一个技巧:把费用设为负,最后再反过来,就可以求最大费用流了。

将S和每个人相连,容量为1, 费用为0,再把每个人和T1点相连(代表第一个属性),容量为1,费用为-a[i],每个人和T2点相连(代表第二个属性),容量为1,费用为-b[i],再把T1和T相连,容量为p,T2和T相连,容量为s。

因为一些粗心调了N久。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 3010
 4 #define INF 0x3f3f3f3f
 5 struct Edge {
 6     int u, v, cap, cost, nxt;
 7 } edge[N*20];
 8 int head[N], a[N], b[N], tot, S, T, vis[N], dis[N], ans, pre[N];
 9 
10 void Add(int u, int v, int cap, int cost) {
11     edge[tot] = (Edge) {u, v, cap, cost, head[u]}; head[u] = tot++;
12     edge[tot] = (Edge) {v, u, 0, -cost, head[v]}; head[v] = tot++;
13 }
14 
15 bool SPFA() {
16     queue<int> que;
17     que.push(S);
18     memset(dis, INF, sizeof(dis));
19     memset(vis, 0, sizeof(vis));
20     int flow = INF;
21     dis[S] = 0; vis[S] = 1; pre[S] = -1;
22     while(!que.empty()) {
23         int u = que.front(); que.pop();
24         vis[u] = 0;
25         for(int i = head[u]; ~i; i = edge[i].nxt) {
26             int v = edge[i].v, w = edge[i].cost;
27             if(edge[i].cap && dis[v] > dis[u] + w) {
28                 dis[v] = dis[u] + w;
29                 pre[v] = i;
30                 flow = min(flow, edge[i].cap);
31                 if(!vis[v]) { vis[v] = 1; que.push(v); }
32             }
33         }
34     }
35     if(dis[T] == INF) return false;
36     ans -= flow * dis[T];
37     int u = T;
38     while(u != S) {
39         edge[pre[u]].cap -= flow;
40         edge[pre[u]^1].cap += flow;
41         u = edge[pre[u]].u;
42     }
43     return true;
44 }
45 
46 int main() {
47     int n, q, p;
48     scanf("%d%d%d", &n, &p, &q);
49     for(int i = 1; i <= n; i++) scanf("%d", a + i);
50     for(int i = 1; i <= n; i++) scanf("%d", b + i);
51     S = 0, T = n + 3; int T1 = n + 1, T2 = n + 2, c1 = 0, c2 = 0;
52     memset(head, -1, sizeof(head)); tot = 0;
53     for(int i = 1; i <= n; i++) {
54         Add(S, i, 1, 0); Add(i, T1, 1, -a[i]); Add(i, T2, 1, -b[i]);
55     }
56     Add(T1, T, p, 0); Add(T2, T, q, 0);
57     ans = 0;
58     while(SPFA()) ;
59     for(int u = 1; u <= n; u++) {
60         for(int i = head[u]; ~i; i = edge[i].nxt) {
61             int v = edge[i].v;
62             if(edge[i].cap == 0) {
63                 if(v == T1) a[++c1] = u;
64                 if(v == T2) b[++c2] = u;
65             }
66         }
67     }
68     printf("%d
", ans);
69     for(int i = 1; i <= c1; i++) printf("%d ", a[i]); puts("");
70     for(int i = 1; i <= c2; i++) printf("%d ", b[i]); puts("");
71     return 0;
72 }
原文地址:https://www.cnblogs.com/fightfordream/p/6401991.html