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

时间:2023-01-22 17:44:52

1449: [JSOI2009]球队收益

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 841  Solved: 483

Description

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

Input

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

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

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

Source

【题意】

 给定n支球队,第i支球队已经赢了win[i]场,输了lose[i]场,接下来还有m场比赛,每个球队最终的收益为Ci∗x[i]^2+Di∗y[i]^2,其中x[i]为最终的胜场,y[i]为最终的负场,求最小化收益。

【分析】

  先差分,再拆边。

  注意,输赢都有贡献,普通做法不行。直接当成那些比赛所有人都输,那只要计算赢的那个人的贡献。

  然后差分:

  赢k-1场:c[i]*(win[i]+(k-1))^2+d[i]*(sm[i]+lose[i]-(k-1))^2

  赢k场:c[i]=(win[i]+k)^2+d[i]*(sm[i]+lose[i]-k)^2

  相减得到赢第k场:c[i]*(2*win[i]-(2*k-1))-d[i]*(2*(lose[i]+sm[i])-(2*k-1))

  这是单调的,所以把原本的贡献+最大费用流就好了。

  可以膜Po姐:http://blog.csdn.net/PoPoQQQ/article/details/46619517

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Maxn 5010
#define Maxm 1010
#define INF 0xfffffff int mymin(int x,int y) {return x<y?x:y;} int win[Maxn],lose[Maxn],c[Maxn],d[Maxn],sm[Maxn]; struct node
{
int x,y,f,c,o,next;
}t[Maxm*];
int len,first[Maxn*]; void ins(int x,int y,int f,int c)
{
t[++len].x=x;t[len].y=y;t[len].f=f;t[len].c=c;
t[len].next=first[x];first[x]=len;t[len].o=len+;
t[++len].x=y;t[len].y=x;t[len].f=;t[len].c=-c;
t[len].next=first[y];first[y]=len;t[len].o=len-;
} queue<int > q;
int st,ed;
int flow[Maxn*],pre[Maxn*],dis[Maxn*];
bool inq[Maxn*];
bool bfs()
{
while(!q.empty()) q.pop();
// memset(dis,-1,sizeof(dis));
for(int i=;i<=ed;i++) dis[i]=INF;
memset(inq,,sizeof(inq));
flow[st]=INF;q.push(st);dis[st]=;
inq[st]=;
while(!q.empty())
{
int x=q.front();
for(int i=first[x];i;i=t[i].next) if(t[i].f>)
{
int y=t[i].y;
if(dis[y]>dis[x]+t[i].c)
{
dis[y]=dis[x]+t[i].c;
pre[y]=i;
flow[y]=mymin(flow[x],t[i].f);
if(!inq[y])
{
q.push(y);
inq[y]=;
}
}
}
q.pop();inq[x]=;
}
if(dis[ed]==INF) return ;
return ;
} int sum=;
int max_flow()
{
while(bfs())
{
int x=ed;
sum+=flow[ed]*dis[ed];
int a=flow[ed];
while(x!=st)
{
t[pre[x]].f-=a;
t[t[pre[x]].o].f+=a;
x=t[pre[x]].x;
}
}
printf("%d\n",sum);
} void output()
{
for(int i=;i<=len;i+=)
printf("%d -> %d %d %d\n",t[i].x,t[i].y,t[i].f,t[i].c);
} int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d%d%d%d",&win[i],&lose[i],&c[i],&d[i]);
st=n+m+;ed=st+;
memset(sm,,sizeof(sm));
for(int i=;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
ins(x,n+i,,);
ins(y,n+i,,);
ins(n+i,ed,,);
sm[x]++;sm[y]++;
}
for(int i=;i<=n;i++)
{
for(int j=;j<=sm[i];j++) ins(st,i,,c[i]*(*win[i]+*j-)-d[i]*(*(sm[i]+lose[i])-(*j-)));
sum+=c[i]*win[i]*win[i]+d[i]*(lose[i]+sm[i])*(lose[i]+sm[i]);
}
max_flow();
return ;
}

2017-04-01 08:20:09