您的位置:首页 > Web前端 > JavaScript

1449/2895: [JSOI2009]球队收益

2018-02-04 11:12 309 查看
题目链接

题目大意:n支球队,球队的支出和胜负场次有关,具体来说,第i支球队的赛季总支出是Ci∗x2+Di∗y2,其中x,y分别表示这只球队本赛季的胜负场次。

现在赛季进行到了一半,每只球队分别取得了ai场胜利和bi场失利。而接下来还有m场比赛要进行。问联盟球队的最小总支出是多少。

题解:输赢都会带来收益……

可以假设初始每只队伍都输,算出初始收益,然后对每场比赛分配赢的队伍

这样每场只要修改赢的那个队伍的收益

从源向每场比赛连流量1费用0的边,从比赛向这场比赛的两支队都连一条流量1费用0的边

由于费用是动态变化的,考虑拆边

对于某支球队,假设后m场中其参加x场,初始w=ai,l=bi+x,之后每赢一场w++,l–−

每只队向汇连x条边,分别代表其赢i场比赛时相对赢i-1场时收益的增量,即

(C∗(w+1)2+D∗(l−1)2)−(C∗w2+D∗l2)=2w∗C−2l∗D+C+D

收益随胜利场数递增,因此一定先走赢比赛场数较少的边,可以保证正确性

答案为所有队伍最初收益+最小费用最大流费用

我的收获:动态费用拆边建图,差分费用……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;

const int N=7505;
const int INF=1e9;

int n,m,ans;
int st,ed;
int t,head
;
int q
,l,r;
int win
,lose
,C
,D
;
int d
,pre
,in
;
bool vis
;

struct edge{int fro,to,nex,c,val;}e[1000000];

void add(int i,int j,int ca,int co){e[t].fro=i,e[t].to=j,e[t].nex=head[i],e[t].c=ca,e[t].val=co;head[i]=t++;}
void insert(int i,int j,int w,int z){add(i,j,w,z),add(j,i,0,-z);}

bool spfa()
{
for(int i=0;i<=ed;i++) vis[i]=0,d[i]=INF;
d[st]=0;l=0,r=0,q[++r]=st;
while(l<r)
{
int u=q[++l];vis[u]=false;
for(int i=head[u];i!=-1;i=e[i].nex){
int v=e[i].to;
if(e[i].c&&d[v]>d[u]+e[i].val){
d[v]=d[u]+e[i].val;
pre[v]=i;
if(!vis[v]){
vis[v]=true;
q[++r]=v;
}
}
}
}
return d[ed]!=INF;
}

void mcfx()
{
int mx=INF;
for(int u=ed;u!=st;u=e[pre[u]].fro)
mx=min(mx,e[pre[u]].c);
for(int u=ed;u!=st;u=e[pre[u]].fro){
e[pre[u]].c-=mx;e[pre[u]^1].c+=mx;
ans+=e[pre[u]].val*mx;
}
}

void work()
{
while(spfa()) mcfx();
printf("%d\n",ans);
}

void build()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=in[i];j++){
insert(i+m,ed,1,2*C[i]*win[i]+C[i]+D[i]-2*D[i]*lose[i]);
lose[i]--;win[i]++;
}
}

void init()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);ed=n+m+1;
for(int i=1;i<=n;i++) scanf("%d%d%d%d",&win[i],&lose[i],&C[i],&D[i]);
for(int u,v,i=1;i<=m;i++){
insert(st,i,1,0);
scanf("%d%d",&u,&v);
insert(i,u+m,1,0),insert(i,v+m,1,0);
in[u]++,in[v]++;
}
for(int i=1;i<=n;i++) lose[i]+=in[i];
for(int i=1;i<=n;i++) ans+=win[i]*win[i]*C[i]+lose[i]*lose[i]*D[i];
build();
}

int main()
{
init();
work();
return 0;
} 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: