bzoj 1449 [JSOI2009]球队收益(费用拆分,最小费用流)

来源:互联网 发布:知乎登录页面 编辑:程序博客网 时间:2024/06/05 06:32

1449: [JSOI2009]球队收益

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 547  Solved: 302
[Submit][Status][Discuss]

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


Source

 

【思路】

       费用拆分,最小费用最大流。

       由S向每场比赛连边(1,0),由每场比赛向两支队伍连边(1,0)。

       考虑在胜w场败l场的基础上再赢一场,则增加cost = ci*w^2+di*l^2-ci*(w+1)^2-di*(l+1)^2=2*ci*w+ci+di+2*di*l的收益。当w增加时cost是单调递增的,所以可以每次相应连一条(1,cost)的边然后w++,l--再次添边直到比赛全部胜利,初始时假设剩余比赛全输。

 

【代码】

 

  1 #include<cstdio>  2 #include<cstring>  3 #include<queue>  4 #include<vector>  5 #define FOR(a,b,c) for(int a=(b);a<(c);a++)  6 using namespace std;  7   8 typedef long long LL ;  9 const int maxn = 8000+10; 10 const int INF = 1e9; 11  12 struct Edge{ int u,v,cap,flow,cost; 13 }; 14 struct zkw { 15     int n,m,s,t; 16     int vis[maxn],d[maxn]; 17     vector<int> G[maxn]; 18     vector<Edge> es; 19      20     void init(int n) { 21         this->n=n; 22         es.clear(); 23         for(int i=0;i<n;i++) G[i].clear(); 24     } 25     void AddEdge(int u,int v,int cap,int cost) { 26         es.push_back((Edge){u,v,cap,0,cost}); 27         es.push_back((Edge){v,u,0,0,-cost}); 28         m=es.size(); 29         G[u].push_back(m-2); 30         G[v].push_back(m-1); 31     } 32     bool spfa() { 33         memset(vis,0,sizeof(vis)); 34         for(int i=0;i<n;i++) d[i]=INF; 35         queue<int> q; 36         d[t]=0 , vis[t]=1 , q.push(t); 37         while(!q.empty()) { 38             int u=q.front(); q.pop() , vis[u]=0; 39             for(int i=0;i<G[u].size();i++) { 40                 Edge& e=es[G[u][i]]; 41                 int v=e.v; 42                 if(es[G[u][i]^1].cap && d[v]>d[u]-e.cost) { 43                     d[v]=d[u]-e.cost; 44                     if(!vis[v]) { 45                         vis[v]=1; 46                         q.push(v); 47                     } 48                 } 49             } 50         } 51         return d[s]!=INF; 52     } 53     int dfs(int u,int a,LL& cost) { 54         vis[u]=1;  if(u==t) return a; 55         int used=0,w; 56         for(int i=0;i<G[u].size();i++) { 57             Edge& e=es[G[u][i]]; 58             int v=e.v; 59             if(d[u]-e.cost==d[v] && !vis[v] && e.cap) { 60                 w=dfs(v,min(a-used,e.cap),cost); 61                 cost+=w*e.cost; 62                 e.cap-=w , es[G[u][i]^1].cap+=w; 63                 used+=w; if(used==a) return a; 64             } 65         } 66         return used; 67     } 68     int Mincost(int s,int t,LL& cost) { 69         this->s=s , this->t=t; 70         int flow=0; cost=0; 71         while(spfa()) { 72             vis[t]=1; 73             while(vis[t]) { 74                 memset(vis,0,sizeof(vis)); 75                 flow+=dfs(s,INF,cost); 76             } 77         } 78         return flow; 79     } 80 } mc; 81  82  83 int n,m; 84 int c[maxn],d[maxn],win[maxn],lose[maxn],in[maxn]; 85  86 int main() { 87     scanf("%d%d",&n,&m); 88     mc.init(n+m+2); 89     int s=n+m,t=s+1; 90     FOR(i,0,n) 91         scanf("%d%d%d%d",&win[i],&lose[i],&c[i],&d[i]); 92     int u,v; 93     FOR(i,0,m) { 94         scanf("%d%d",&u,&v); 95         u--,v--;  96         in[u]++,in[v]++; 97         mc.AddEdge(s,i,1,0); 98         mc.AddEdge(i,m+u,1,0); 99         mc.AddEdge(i,m+v,1,0);100     }101     LL ans=0;102     FOR(i,0,n) {103         lose[i]+=in[i];104         ans+=c[i]*win[i]*win[i]+d[i]*lose[i]*lose[i];105     }106     FOR(i,0,n) {107         FOR(j,0,in[i]) {108             mc.AddEdge(m+i,t,1,2*c[i]*win[i]+c[i]+d[i]-2*d[i]*lose[i]);109             lose[i]-- , win[i]++;110         }111     }112     LL cost;113     mc.Mincost(s,t,cost);114     printf("%lld",cost+ans);115     return 0;116 }

 

0 0
原创粉丝点击