• 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 }
  • 相关阅读:
    Windows DLL调用实例
    DLL头文件的格式和应用
    Strategy factory
    抽象数据类型(ADT)和面向对象编程(OOP)3.5 ADT和OOP中的等价性
    抽象数据类型(ADT)和面向对象编程(OOP)3.4 面向对象的编程
    抽象数据类型(ADT)和面向对象编程(OOP)3.3 抽象数据类型
    抽象数据类型(ADT)和面向对象编程(OOP)3.2规约
    抽象数据类型(ADT)和面向对象编程(OOP)3.1数据类型和类型检查
    软件构造 消息传递
    软件构造 并发3(线程安全性)----锁定和同步
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6401991.html
Copyright © 2020-2023  润新知