首页 > 代码库 > 【BZOJ1449/2895】[JSOI2009]球队收益/球队预算 最小费用最大流

【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行每行两个整数s,t表示第s支队伍和第t支队伍之间将有一场比赛,注意两只队间可能有多场比赛。

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
Data Limit
对于20%的数据2<=n<=10,0<=m<=20
对于100%的数据2<=n<=5000,0<=m<=1000,0<=di<=ci<=10,0<=a[i],b[i]<=50.

题解:一开始naive了,建了一个8层的费用流模型,把自己都吓傻了~

本题有一个不容易处理的要求,就是每场比赛只能有一队胜出,那我们不妨假设一开始所有球队的每场比赛都输了,然后我们有m个流量,每有一个流量流到一个队就代表这个队赢了一次,然后就很好处理了。

#include <cstdio>#include <cstring>#include <iostream>#include <queue>using namespace std;int cnt,n,m,sum,mf,S,T;int to[1000000],next[1000000],cost[1000000],flow[1000000],pe[10000],pv[10000],head[10000],dis[10000];int A[10000],B[10000],C[10000],D[10000],E[10000],inq[10000];queue<int> q;int rd(){	int ret=0,f=1;	char gc=getchar();	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();	return ret*f;}void add(int a,int b,int c,int d){	to[cnt]=b,cost[cnt]=c,flow[cnt]=d,next[cnt]=head[a],head[a]=cnt++;	to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++;}int bfs(){	memset(dis,0x3f,sizeof(dis));	int i,u;	q.push(S),dis[S]=0;	while(!q.empty())	{		u=q.front(),q.pop(),inq[u]=0;		for(i=head[u];i!=-1;i=next[i])		{			if(dis[to[i]]>dis[u]+cost[i]&&flow[i])			{				dis[to[i]]=dis[u]+cost[i],pv[to[i]]=u,pe[to[i]]=i;				if(!inq[to[i]])	q.push(to[i]),inq[to[i]]=1;			}		}	}	return dis[T]<0x3f3f3f3f;}int main(){	n=rd(),m=rd();	int i,j,a,b;	S=0,T=n+m+1;	memset(head,-1,sizeof(head));	for(i=1;i<=n;i++)	A[i]=rd(),B[i]=rd(),C[i]=rd(),D[i]=rd();	for(i=1;i<=m;i++)	a=rd(),b=rd(),E[a]++,E[b]++,add(S,n+i,0,1),add(n+i,a,0,1),add(n+i,b,0,1);	for(i=1;i<=n;i++)		{		sum+=C[i]*A[i]*A[i]+D[i]*(E[i]+B[i])*(E[i]+B[i]);		for(j=1;j<=E[i];j++)	add(i,T,C[i]*(2*(A[i]+j-1)+1)-D[i]*(2*(B[i]+E[i]-j)+1),1);	}	while(bfs())	{		mf=1<<30;		for(i=T;i!=S;i=pv[i])	mf=min(mf,flow[pe[i]]);		sum+=mf*dis[T];		for(i=T;i!=S;i=pv[i])	flow[pe[i]]-=mf,flow[pe[i]^1]+=mf;	}	printf("%d",sum);	return 0;}

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