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\n", 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 }