[JSOI2009]球队收益

1449: [JSOI2009]球队收益

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 1124  Solved: 635
[Submit][Status][Discuss]

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

Source

二次费用流模板题。

我们先假设每个队剩下的比赛都输,然后用费用流来让每次比赛的两队之一获胜。

考虑从S向每个比赛连一条容量为1的边,从每个比赛向另两个球队也连容量为1 的边。

注意上述边都是没有边权的。

那么考虑一个球队多赢一场的影响?

derta[x] = C*(2*win[x]+1) - D*(2*lose[x]-1)  ,其中win是输入的,lose为输入的加上之后这个队的比赛数。

发现随着一个队赢的次数增多,这个derta会越来越大,而我们费用流是优先走小的边,正好符合先后顺序。

所以最小费用最大流的情况一定符合最优解。

#include<bits/stdc++.h>
#define ll long long
#define maxn 30005
#define pb push_back
using namespace std;
const int inf=1<<30;
struct lines{
	int from,to,flow,cap,cost;
}l[maxn*10];
ll tot=0;
vector<int> g[maxn];
int S,T,t=-1,d[maxn];
int a[maxn],p[maxn];
bool iq[maxn];

inline void add(int from,int to,int cap,int cost){
	l[++t]=(lines){from,to,0,cap,cost},g[from].pb(t);
	l[++t]=(lines){to,from,0,0,-cost},g[to].pb(t);
}

inline bool BFS(){
	queue<int> q;
	memset(d,0x3f,sizeof(d));
	d[S]=0,p[S]=0,a[S]=inf;
	iq[S]=1,q.push(S);
	int x; lines e;

	while(!q.empty()){
		x=q.front(),q.pop();
		for(int i=g[x].size()-1;i>=0;i--){
			e=l[g[x][i]];
			if(e.flow<e.cap&&d[x]+e.cost<d[e.to]){
				d[e.to]=d[x]+e.cost;
				a[e.to]=min(a[x],e.cap-e.flow);
				p[e.to]=g[x][i];
				if(!iq[e.to]) iq[e.to]=1,q.push(e.to);
			}
		}

		iq[x]=0;
	}

	if(d[T]==d[T+1]) return 0;

	tot+=a[T]*(ll)d[T];

	int now=T,pre;
	while(now!=S){
		pre=p[now];
		l[pre].flow+=a[T];
		l[pre^1].flow-=a[T];
		now=l[pre].from;
	}

	return 1;
}

int n,m,C[5005],D[5005];
int win[5005],lose[5005];
int cnt=0,X[1005],Y[1005];

inline int sq(int x){
	return x*x;
}

inline void MFMC(){
	while(BFS());
}

inline void build(){
	for(int i=1;i<=n;i++){
		tot+=C[i]*sq(win[i])+D[i]*sq(lose[i]);
	}
	for(int i=1;i<=m;i++){
		add(S,i+n,1,0);
		add(i+n,X[i],1,0);
		add(i+n,Y[i],1,0);
		add(X[i],T,1,-D[X[i]]*(2*lose[X[i]]-1)+C[X[i]]*(2*win[X[i]]+1));
		win[X[i]]++,lose[X[i]]--;
		add(Y[i],T,1,-D[Y[i]]*(2*lose[Y[i]]-1)+C[Y[i]]*(2*win[Y[i]]+1));
		win[Y[i]]++,lose[Y[i]]--;
	}

}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d%d",win+i,lose+i,C+i,D+i);
	}
	S=0,T=m+n+1;
	for(int i=1;i<=m;i++){
		scanf("%d%d",X+i,Y+i);
		lose[X[i]]++,lose[Y[i]]++;
	}

	build();

	MFMC();

	printf("%lld\n",tot);
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8536425.html

时间: 2024-10-01 02:59:50

[JSOI2009]球队收益的相关文章

bzoj 1449 [JSOI2009]球队收益(费用拆分,最小费用流)

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 547  Solved: 302[Submit][Status][Discuss] 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 Source [思路] 费用拆分,

BZOJ 1449: [JSOI2009]球队收益( 最小费用最大流)

先考虑假如全部输了的收益. 再考虑每场比赛球队赢了所得收益的增加量,用这个来建图.. -------------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<iostre

bzoj1449 [JSOI2009]球队收益

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 orz huzecong 神犇的想法果然与众不同 首先看上去像网络流.这样就够了 先假设每场比赛两队都是输的,那么接下来转换的时候只要把其中一对变成赢的就好了. 考虑一支球队已经赢了x场输了y场现在要把输的y场之一变成赢的,考虑这样对答案的影响 原来是C[i]*

【bzoj1449/bzoj2895】[JSOI2009]球队收益/球队预算 费用流

题目描述 输入 输出 一个整数表示联盟里所有球队收益之和的最小值. 样例输入 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 样例输出 43 题解 费用流 由于存在一个赢一个输,比较难算.我们可以先假设它们都输掉,然后再安排赢的情况. 设fi为i还要打的比赛数目,那么初始的收益为∑ci*wi^2+di*(li+fi)^2. S->每场比赛,容量为1,费用为0. 每场比赛->比赛的两队,容量为1,费用为0. 因为费用的改变是包含平方的,所以我们需要拆边来做. 第

BZOJ 1449 JSOI2009 球队收益 费用流

题目大意:给定n支球队,第i支球队已经赢了wini场,输了losei场,接下来还有m场比赛,每个球队最终的收益为Ci?x2i+Di?y2i,其中xi为最终的胜场,yi为最终的负场 求最小化收益 考虑一只球队,其收益与在接下来的比赛中的胜场数关系为: 赢0场 Ci?win2i+Di?(di+losei)2 赢1场 Ci?(wini+1)2+Di?(di+losei?1)2 赢2场 Ci?(wini+2)2+Di?(di+losei?2)2 - 赢di场 Ci?(wini+di)2+Di?lose2

【BZOJ1449/2895】[JSOI2009]球队收益/球队预算 最小费用最大流

[BZOJ2895]球队预算 Description 在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是Ci*x^2+Di*y^2,Di<=Ci.(赢得多,给球员的奖金就多嘛) 其中x,y分别表示这只球队本赛季的胜负场次.现在赛季进行到了一半,每只球队分别取得了a[i]场胜利和b[i]场失利.而接下来还有m场比赛要进行.问联盟球队的最小总支出是多少. Input 第一行n,m 接下来n行每行4个整数a[i],b[i],Ci,Di 再接下来m行每

【题解】JSOI2009球队收益 / 球队预算

为什么大家都不写把输的场次增加的呢?我一定要让大家知道,这并没有什么关系~所以 \(C[i] <= D[i]\) 的条件就是来卖萌哒?? #include <bits/stdc++.h> using namespace std; #define maxn 1000000 #define INF 99999999 int n, m, S, T, rec[maxn], flow[maxn], a[maxn], b[maxn]; int ans, tot, c[maxn], d[maxn],

[JSOI2009] 球队收益 (费用流)

终于来发题解啦! pdf版题解 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<climits> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9

【BZOJ-1449&amp;2895】球队收益&amp;球队预算 最小费用最大流

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 648  Solved: 364[Submit][Status][Discuss] 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 Source 2895: 球队预算