bzoj1449: [JSOI2009]球队收益
Description
Input
Output
一个整数表示联盟里所有球队收益之和的最小值。
Sample Input
3 3
1 0 2 1
1 1 10 1
0 1 3 3
1 2
2 3
3 1
1 0 2 1
1 1 10 1
0 1 3 3
1 2
2 3
3 1
Sample Output
43
HINT
题解:
这道题可以像wc2007石头剪刀布那样由S向每场比赛连一条容量为1费用为0的边,由每场比赛向两个人分别连容量为1费用为0的边
现在要处理每个人如何向T连边
假设i号队伍赢了x场输了y场,假如将i号队输了的某局改为i号队赢了,那么收益变化了c(x+1)2+d(y-1)2-cx2-dy2=2cx-2dy+c+d
设i号队将要参加的比赛数为rest[i]
我们先假设i队未确定的比赛都输了,那么由i号队向T连rest条边,容量均为1,费用分别为 2c*win[i]-2d*(lose[i]+rest[i])+c+d , 2c*(win[i]+1)-2d*(lose[i]+rest[i]-1)+c+d , ... , 2c*(win[i]+rest[i])-2d*lose[i]+c+d
答案就是初始收益(假设了未确定的比赛都输了)+ 最小费用最大流的费用
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 6005 7 #define maxm 20000 8 #define inf 1061109567 9 using namespace std; 10 char ch; 11 bool ok; 12 void read(int &x){ 13 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 14 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 15 if (ok) x=-x; 16 } 17 int n,m,a[1005],b[1005],ans,win[5005],lose[5005],rest[5005],c[5005],d[5005]; 18 struct costflow{ 19 int s,t,tot,now[maxn],son[maxm],pre[maxm],val[maxm],cost[maxm]; 20 int dis[maxn],head,tail,list[maxn],tmp,totflow,totcost; 21 bool bo[maxn]; 22 void init(){s=0,t=n+m+1,tot=1,memset(now,0,sizeof(now));} 23 void put(int a,int b,int c,int d){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c,cost[tot]=d;} 24 void add(int a,int b,int c,int d){put(a,b,c,d),put(b,a,0,-d);} 25 void spfa(){ 26 memset(bo,0,sizeof(bo)); 27 memset(dis,63,sizeof(dis)); 28 head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1; 29 while (head<tail){ 30 if (++head==maxn) head=1; 31 int u=list[head]; 32 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 33 if (val[p]&&dis[v]>dis[u]+cost[p]){ 34 dis[v]=dis[u]+cost[p]; 35 if (!bo[v]){ 36 if (++tail==maxn) tail=1; 37 list[tail]=v,bo[v]=1; 38 } 39 } 40 bo[u]=0; 41 } 42 } 43 int dfs(int u,int rest,int totval){ 44 bo[u]=1; 45 if (u==t){totcost+=rest*totval;return rest;} 46 int ans=0; 47 for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p]) 48 if (val[p]&&!bo[v]&&dis[v]==dis[u]+cost[p]){ 49 int d=dfs(v,min(rest,val[p]),totval+cost[p]); 50 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d; 51 } 52 return ans; 53 } 54 bool relax(){ 55 int d=inf; 56 for (int u=s;u<=t;u++) if (bo[u]) 57 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 58 if (val[p]&&!bo[v]) d=min(d,dis[u]+cost[p]-dis[v]); 59 if (d==inf) return false; 60 for (int u=s;u<=t;u++) if (!bo[u]) dis[u]+=d; 61 return true; 62 } 63 void work(){ 64 spfa(),totflow=totcost=0; 65 do{ 66 do{ 67 memset(bo,0,sizeof(bo)); 68 tmp=dfs(s,inf,0),totflow+=tmp; 69 }while (tmp); 70 }while (relax()); 71 } 72 }f; 73 int main(){ 74 read(n),read(m),f.init(); 75 for (int i=1;i<=n;i++) read(win[i]),read(lose[i]),read(c[i]),read(d[i]); 76 for (int i=1;i<=m;i++) read(a[i]),read(b[i]),rest[a[i]]++,rest[b[i]]++; 77 for (int i=1;i<=n;i++){ 78 for (int x=win[i],y=lose[i]+rest[i];y>lose[i];x++,y--) 79 f.add(i,f.t,1,(c[i]<<1)*x-(d[i]<<1)*y+c[i]+d[i]); 80 lose[i]+=rest[i],ans+=c[i]*win[i]*win[i]+d[i]*lose[i]*lose[i]; 81 } 82 for (int i=1;i<=m;i++) f.add(f.s,n+i,1,0),f.add(n+i,a[i],1,0),f.add(n+i,b[i],1,0); 83 f.work(); 84 printf("%d\n",ans+f.totcost); 85 return 0; 86 }