[bzoj 1449] 球队收益(费用流)


Description

Input

Output

一个整数表示联盟里所有球队收益之和的最小值。

Sample Input

3 3

1 0 2 1

1 1 10 1

0 1 3 3

1 2

2 3

3 1

Sample Output

43

Hint


Solution

这题费用流裸题好吧。

先假设所有队在接下来的比赛中都会输掉,算出收益。

但是一场比赛应该有且只有一支球队赢得比赛,所以真实收益和我们算出来的收益就会有一些差值,再计算最小的差值即可。

我们可以发现,队伍\(i\)每赢得一场比赛,就会多获得\(C_i * (2 * Win_i + 1) - D_i * (2 * Lost_i - 1)\) 的收益,并且由于赢得越多,\(Win_i\)就会越大,\(Lost_i\)就会越小,所以获得的收益差值就会越来越大。 于是我们可以建立一个最小费用最大流的模型。

  1. 我们建立一个源点,向所有比赛建一条流量为1,费用为0的边。
  2. 从比赛向其两支球队建立一条流量为1,费用为0的边。
  3. 从每支球队向汇点建x(x是该支球队参加的比赛数)条边,每条边流量为1,费用每赢一场的差值。

PS: 这里要注意一点,差值会随着赢的场数增多而增多,所以最小费用最大流一定会先走赢第一场,再走第二场,第三场,等等。。。这是算法正确性的关键。

建好图,然后跑一遍最小费用最大流,加上之前的答案,这题就完了。

Code

#include <cstdio>
#include <queue>
#include <iostream>
using namespace std; const int maxn = 5e3 + 10, maxm = 1e3 + 10, inf = 1e9 + 7;
int n, m, S, T, cnt;
int w[maxn], l[maxn], a[maxn], b[maxn], x[maxn];
int dis[maxn+maxm], inq[maxn+maxm];
queue<int> q;
struct edge {int u, v, f, c; edge *next, *rev;} e[maxn<<1], *head[maxn+maxm], *from[maxn+maxm]; inline void adde(int u, int v, int flow, int cost) {
e[cnt] = (edge){u, v, flow, cost, head[u], &e[cnt+1]}, head[u] = &e[cnt++];
e[cnt] = (edge){v, u, 0, -cost, head[v], &e[cnt-1]}, head[v] = &e[cnt++];
} bool spfa() {
while(!q.empty()) q.pop();
for(int i = 1; i <= m + n + 1; i++) dis[i] = inf, inq[i] = 0, from[i] = NULL;
dis[S] = 0, inq[S] = 1; q.push(S);
while(!q.empty()) {
int u = q.front(); q.pop(), inq[u] = 0;
for(edge *k = head[u]; k; k = k->next) if(k->f) {
if(dis[k->v] > dis[u] + k->c) {
dis[k->v] = dis[u] + k->c;
from[k->v] = k;
if(!inq[k->v]) inq[k->v] = 1, q.push(k->v);
}
}
}
return dis[T] != inf;
} int mcf() {
int res = 0, xx = inf;
for(edge *k = from[T]; k; k = from[k->u]) xx = min(xx, k->f);
for(edge *k = from[T]; k; k = from[k->u])
res += xx * k->c, k->f -= xx, k->rev->f += xx;
return res;
} int main() {
int u, v;
scanf("%d%d", &n, &m);S = 0, T = n + m + 1;
for(int i = 1; i <= n; i++) scanf("%d%d%d%d", w+i, l+i, a+i, b+i);
for(int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
l[u]++, l[v]++;
x[u]++, x[v]++;
adde(S, n+i, 1, 0);
adde(n + i, u, 1, 0);
adde(n + i, v, 1, 0);
}
int ans = 0;
for(int i = 1; i <= n; i++) {
ans += w[i] * w[i] * a[i] + l[i] * l[i] * b[i];
for(int j = 0; j < x[i]; j++)
adde(i, T, 1, a[i]*(2*w[i]+1) - b[i] * (2 * l[i] - 1)),
w[i]++, l[i]--;
}
while(spfa()) ans += mcf();
printf("%d\n", ans);
return 0;
}

最新文章

  1. 推荐10个bootstrap及其他框架的后台管理模板
  2. 数据库防火墙如何防范SQL注入行为
  3. 特征值提取之 -- TF-IDF值的简单介绍
  4. 分区的4k对齐
  5. Task 使用 Task以及Task.Factory都是在.Net 4引用的。Task跟Thread很类似,通过下面例子可以看到。
  6. 叠罗汉III之推箱子
  7. IOS开发中的几种设计模式
  8. linux 参数优化
  9. 【转】.NET开发人员的瓶颈和职业发展
  10. (转载)Flash Number 数据类型
  11. css以及选择器基础
  12. SourceTree for Mac 破解版
  13. CF266D. BerDonalds [图的绝对中心]
  14. PAT All Roads Lead to Rome 单源最短路
  15. tornado 采用 epoll 代理构建高并发网络模型
  16. [ExtJS5学习笔记]第十一节 Extjs5MVVM模式下系统登录实例
  17. kali的网络服务
  18. C# 通用数据库配置界面,微软原生DLL重整合
  19. MySQL中format()函数
  20. ReentrantLock源码(一)

热门文章

  1. react-native 适配问题
  2. RichEditControl(富文本控件)
  3. 作为使用者对qq拼音输入法和搜狗输入法的评价
  4. commons-lang3-RandomUtils
  5. Java多线程中Lock的使用
  6. window下安装tensowflow
  7. Maven转换成Eclipse/Idea/MyEclipse工程,以及配置Web工程
  8. eclipse中通过search打开第二个文件时 第一个文件就自己关闭了
  9. 【ActiveMQ】2.spring Boot下使用ActiveMQ
  10. 7.【nuxt起步】-Nuxt与后端数据交互