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

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 }

 

posted @ 2016-01-19 21:24  chenyushuo  阅读(177)  评论(0编辑  收藏  举报