洛谷P4307 球队收益

题意:有n个球队,m场比赛。

每个球队都已经有些胜负场次了。

每个球队的收益为Ci * wini2 - Di * losei2

求最小可能总收益。

解:

先看出一个模型:用一流量代表一个胜场,每场比赛向两支队伍连边。

然后我们发现这个费用是跟流量的平方有关的,How to do?

先观察一波:1 4 9 16 25

差分:1 3 5 7 9

然后我们就发现:如果把下面差分建成边的费用,限流为1,恰好就是收益了。

至此茅塞顿开。

首先假设所有的队伍都输了,然后每场选出一名胜者,C(2win + 1) - D(2lose - 1)为费用。

最小费用最大流即可。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <queue>
  4 #include <cstring>
  5 
  6 const int N = 6050, M = 1000010;
  7 const int INF = 0x3f3f3f3f;
  8 
  9 struct Edge {
 10     int nex, v;
 11     int c, len;
 12 }edge[M << 1]; int top = 1;
 13 
 14 int e[N], vis[N], pre[N];
 15 int d[N], flow[N];
 16 std::queue<int> Q;
 17 int A[N], B[N], C[N], D[N], win[N], los[N], X[N], Y[N];
 18 
 19 inline void add(int x, int y, int z, int w) {
 20     //printf("add : %d %d \n", x, y);
 21     top++;
 22     edge[top].v = y;
 23     edge[top].c = z;
 24     edge[top].len = w;
 25     edge[top].nex = e[x];
 26     e[x] = top;
 27 
 28     top++;
 29     edge[top].v = x;
 30     edge[top].c = 0;
 31     edge[top].len = -w;
 32     edge[top].nex = e[y];
 33     e[y] = top;
 34     return;
 35 }
 36 
 37 inline bool SPFA(int s, int t) {
 38     memset(d, 0x3f, sizeof(d));
 39     d[s] = 0;
 40     flow[s] = INF;
 41     vis[s] = 1;
 42     Q.push(s);
 43     while(!Q.empty()) {
 44         int x = Q.front();
 45         Q.pop();
 46         vis[x] = 0;
 47         //printf("x = %d d = %d\n", x, d[x]);
 48         for(int i = e[x]; i; i = edge[i].nex) {
 49             int y = edge[i].v;
 50             if(edge[i].c && d[y] > d[x] + edge[i].len) {
 51                 d[y] = d[x] + edge[i].len;
 52                 pre[y] = i;
 53                 flow[y] = std::min(flow[x], edge[i].c);
 54                 if(!vis[y]) {
 55                     vis[y] = 1;
 56                     Q.push(y);
 57                 }
 58             }
 59         }
 60     }
 61     return d[t] < INF;
 62 }
 63 
 64 inline void update(int s, int t) {
 65     int temp = flow[t];
 66     while(t != s) {
 67         int i = pre[t];
 68         edge[i].c -= temp;
 69         edge[i ^ 1].c += temp;
 70         t = edge[i ^ 1].v;
 71     }
 72     return;
 73 }
 74 
 75 inline int solve(int s, int t, int &cost) {
 76     int ans = 0;
 77     cost = 0;
 78     while(SPFA(s, t)) {
 79         ans += flow[t];
 80         cost += flow[t] * d[t];
 81         update(s, t);
 82     }
 83     return ans;
 84 }
 85 
 86 int main() {
 87     int n, m, s, t, sum = 0;
 88     scanf("%d%d", &n, &m);
 89     s = n + m + 1, t = m + n + 2;
 90     for(int i = 1; i <= n; i++) {
 91         scanf("%d%d%d%d", &win[i], &los[i], &C[i], &D[i]);
 92         /*win[i] = A[i];
 93         los[i] = B[i];*/
 94     }
 95     for(int i = 1; i <= m; i++) {
 96         scanf("%d%d", &X[i], &Y[i]);
 97         add(s, n + i, 1, 0);
 98         add(n + i, X[i], 1, 0);
 99         add(n + i, Y[i], 1, 0);
100         los[X[i]]++;
101         los[Y[i]]++;
102     }
103     for(int i = 1; i <= n; i++) {
104         sum += C[i] * win[i] * win[i];
105         sum += D[i] * los[i] * los[i];
106     }
107     for(int i = 1; i <= m; i++) {
108         int x = X[i], y = Y[i];
109         add(x, t, 1, C[x] * (2 * win[x] + 1) - D[x] * (2 * los[x] - 1));
110         add(y, t, 1, C[y] * (2 * win[y] + 1) - D[y] * (2 * los[y] - 1));
111         win[x]++;
112         win[y]++;
113         los[x]--;
114         los[y]--;
115     }
116 
117     int ans;
118     solve(s, t, ans);
119     printf("%d", ans + sum);
120     return 0;
121 }
AC代码

 

posted @ 2018-12-13 19:17  huyufeifei  阅读(224)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜