• 【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;
    }
  • 相关阅读:
    [ASP.NET] 使用 ASP.NET SignalR 添加实时 Web
    [ORM] Entity Framework(2) CodeFirst进阶
    [ORM] Entity Framework(1) CodeFirst快速入门
    [C#] 谈谈异步编程async await
    [Solution] NPOI操作Excel
    消息队列二
    消息队列一
    redis成长之路——(七)
    redis成长之路——(六)
    redis成长之路——(五)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6999910.html
Copyright © 2020-2023  润新知