BZOJ2895: 球队预算
【传送门:BZOJ2895】
简要题意:
在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是Ci*x^2+Di*y^2,Di<=Ci。(赢得多,给球员的奖金就多嘛),其中x,y分别表示这只球队本赛季的胜负场次。现在赛季进行到了一半,每只球队分别取得了a[i]场胜利和b[i]场失利。而接下来还有m场比赛要进行。问联盟球队的最小总支出是多少。
题解:
费用流
参考代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,c,d,next,other; int el; node() { d=0; } }a[110000];int len,last[6100]; void ins(int x,int y,int c,int d) { int k1=++len,k2=++len; a[k1].x=x;a[k1].y=y;a[k1].c=c;a[k1].d=d; a[k1].next=last[x];last[x]=k1; a[k2].x=y;a[k2].y=x;a[k2].c=0;a[k2].d=-d; a[k2].next=last[y];last[y]=k2; a[k1].other=k2; a[k2].other=k1; } int st,ed; int list[6100]; int d[6100]; bool v[6100]; int ans; int pos[6100],pre[6100]; bool spfa() { for(int i=st;i<=ed;i++) d[i]=999999999; d[st]=0; memset(v,false,sizeof(v)); v[st]=true; int head=1,tail=2; list[1]=st; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&d[y]>d[x]+a[k].d) { d[y]=d[x]+a[k].d; pos[y]=x; pre[y]=k; if(v[y]==false) { v[y]=true; list[tail++]=y; } } } head++; v[x]=false; } if(d[ed]==999999999) return false; else return true; } int w[5100],l[5100],C[5100],D[5100]; void Flow() { while(spfa()) { ans+=d[ed]; for(int x=ed;x!=st;x=pos[x]) { a[pre[x]].c--; a[a[pre[x]].other].c++; } } } int s[5100]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d%d%d",&w[i],&l[i],&C[i],&D[i]); int sum=0; st=0;ed=m+n+1; memset(s,0,sizeof(s)); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); s[x]++;s[y]++; ins(st,i,1,0); ins(i,x+m,1,0); ins(i,y+m,1,0); l[x]++;l[y]++; } for(int i=1;i<=n;i++) ans+=C[i]*w[i]*w[i]+D[i]*l[i]*l[i]; //C[i]*2*w[i]+C[i]-D[i]*2*l[i]+D[i] for(int i=1;i<=n;i++) { for(int j=1;j<=s[i];j++) { ins(i+m,ed,1,C[i]*2*w[i]+C[i]-D[i]*2*l[i]+D[i]); w[i]++;l[i]--; } } Flow(); printf("%d\n",ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚