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

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 }
时间: 2024-10-12 22:38:11

bzoj 1449 [JSOI2009]球队收益(费用拆分,最小费用流)的相关文章

BZOJ 1449 JSOI2009 球队收益 费用流

题目大意:给定n支球队,第i支球队已经赢了wini场,输了losei场,接下来还有m场比赛,每个球队最终的收益为Ci?x2i+Di?y2i,其中xi为最终的胜场,yi为最终的负场 求最小化收益 考虑一只球队,其收益与在接下来的比赛中的胜场数关系为: 赢0场 Ci?win2i+Di?(di+losei)2 赢1场 Ci?(wini+1)2+Di?(di+losei?1)2 赢2场 Ci?(wini+2)2+Di?(di+losei?2)2 - 赢di场 Ci?(wini+di)2+Di?lose2

BZOJ 1449: [JSOI2009]球队收益( 最小费用最大流)

先考虑假如全部输了的收益. 再考虑每场比赛球队赢了所得收益的增加量,用这个来建图.. -------------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<iostre

[JSOI2009]球队收益

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1124  Solved: 635[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 二次费用流模板题.

【bzoj1449/bzoj2895】[JSOI2009]球队收益/球队预算 费用流

题目描述 输入 输出 一个整数表示联盟里所有球队收益之和的最小值. 样例输入 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 样例输出 43 题解 费用流 由于存在一个赢一个输,比较难算.我们可以先假设它们都输掉,然后再安排赢的情况. 设fi为i还要打的比赛数目,那么初始的收益为∑ci*wi^2+di*(li+fi)^2. S->每场比赛,容量为1,费用为0. 每场比赛->比赛的两队,容量为1,费用为0. 因为费用的改变是包含平方的,所以我们需要拆边来做. 第

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 orz huzecong 神犇的想法果然与众不同 首先看上去像网络流.这样就够了 先假设每场比赛两队都是输的,那么接下来转换的时候只要把其中一对变成赢的就好了. 考虑一支球队已经赢了x场输了y场现在要把输的y场之一变成赢的,考虑这样对答案的影响 原来是C[i]*

【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行每

[JSOI2009] 球队收益 (费用流)

终于来发题解啦! pdf版题解 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<climits> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9

bozj 1449/2895: 球队预算 -- 费用流

2895: 球队预算 Time Limit: 10 Sec  Memory Limit: 256 MB Description 在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是Ci*x^2+Di*y^2,Di<=Ci.(赢得多,给球员的奖金就多嘛) 其中x,y分别表示这只球队本赛季的胜负场次.现在赛季进行到了一半,每只球队分别取得了a[i]场胜利和b[i]场失利.而接下来还有m场比赛要进行.问联盟球队的最小总支出是多少. Input 第一行n

【题解】JSOI2009球队收益 / 球队预算

为什么大家都不写把输的场次增加的呢?我一定要让大家知道,这并没有什么关系~所以 \(C[i] <= D[i]\) 的条件就是来卖萌哒?? #include <bits/stdc++.h> using namespace std; #define maxn 1000000 #define INF 99999999 int n, m, S, T, rec[maxn], flow[maxn], a[maxn], b[maxn]; int ans, tot, c[maxn], d[maxn],