【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;
}
posted @ 2017-06-13 10:44  CQzhangyu  阅读(223)  评论(0编辑  收藏  举报