[JSOI2009]球队收益 / 球队预算

Description:

在一个篮球联赛里,有\(n\)支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是\(C_i\times x^2+D_i \times y^2,D_i \le C_i\)。(赢得多,给球员的奖金就多嘛)
其中\(x,y\)分别表示这只球队本赛季的胜负场次。现在赛季进行到了一半,每只球队分别取得了\(a_i\)场胜利和\(b_i\)场失利。而接下来还有\(m\)场比赛要进行。问联盟球队的最小总支出是多少.

Hint:

对于100%的数据\(2 \le n \le 5000,0 \le m \le 1000,0 \le D_i \le C_i \le 10,0 \le a_i,b_i \le 50\)

Solution:

费用流神仙题

首先如果想直接连边的话,会发现由于无法确定\(a[i]\),\(b[i]\)而无从下手

所以我们要转化模型,先令所有队伍双方都输了,然后考虑一个队赢对答案的贡献:

\[C _i+2*a_i*C_i+D_i-2*b_i*D_i \]

这个式子会随着\(a[i]\)最大而增大(听说叫做增量模型)

所以我们可以考虑把每个队向T连\(a[i]\)条费用为上述的边

分别对应所有赢的情况(有点像修车那题)

然后把S连向m场比赛容1费0,再把比赛分别连向那两个队容1费0

答案就是输的总贡献+最小费用

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=1e5+5;
int n,m,S,T,ans,cnt,cost,sum, a[mxn],b[mxn],c[mxn],d[mxn],e[mxn],hd[mxn];
int pre[mxn],f[mxn],vis[mxn],dis[mxn],bl[mxn];

inline int read() {
	char c=getchar(); int x=0,f=1;
	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
	return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
	int to,nxt,w,val;
}t[mxn<<1];

inline void add(int u,int v,int w,int z) {
	t[cnt]=(ed) {v,hd[u],w,z}; hd[u]=cnt++;
	t[cnt]=(ed) {u,hd[v],0,-z}; hd[v]=cnt++;
}

int spfa() {
	memset(vis,0,sizeof(vis));
	memset(pre,0,sizeof(pre));
	memset(dis,0x3f,sizeof(dis));
	memset(f,0x3f,sizeof(f));
	queue<int > q; q.push(S);
	dis[S]=pre[S]=0;
	while(!q.empty()) {
		int u=q.front(); q.pop(); vis[u]=0;
		for(int i=hd[u];i!=-1;i=t[i].nxt) {
			int v=t[i].to;
			if(t[i].w>0&&dis[v]>dis[u]+t[i].val) {
				dis[v]=dis[u]+t[i].val; pre[v]=u;
				bl[v]=i; f[v]=min(f[u],t[i].w);
				if(!vis[v]) q.push(v),vis[v]=1;
			}
		}
	}
	return pre[T];
}

void Dinic() {
	while(spfa()) {
		ans+=f[T];
		cost+=f[T]*dis[T];
		for(int i=T;i!=S;i=pre[i]) {
			t[bl[i]].w-=f[T];
			t[bl[i]^1].w+=f[T];
		}
	}
}

int main()
{
	n=read(); m=read(); S=n+m+1,T=S+1; int x,y; memset(hd,-1,sizeof(hd));
	for(int i=1;i<=n;++i) a[i]=read(),b[i]=read(),c[i]=read(),d[i]=read();
	for(int i=1;i<=m;++i) {
		x=read(); y=read(); 
		++b[x],++b[y],++e[x],++e[y];
		add(S,i,1,0); 
		add(i,x+m,1,0);
		add(i,y+m,1,0);
	}
	for(int i=1;i<=n;++i)	
		sum+=c[i]*a[i]*a[i]+d[i]*b[i]*b[i];
	for(int i=1;i<=n;++i) 
		for(int j=1;j<=e[i];++j) {
			add(i+m,T,1,c[i]+2*a[i]*c[i]+d[i]-2*b[i]*d[i]);
			--b[i]; ++a[i];
		}
	Dinic();	
	printf("%d",sum+cost);	
    return 0;
}


posted @ 2019-03-25 22:43  cloud_9  阅读(152)  评论(0编辑  收藏  举报