【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; }
| 欢迎来原网站坐坐! >原文链接<