BZOJ 1449 JSOI2009 球队收益 费用流

来源:互联网 发布:手机地球仪软件中文版 编辑:程序博客网 时间:2024/05/28 05:18

题目大意:给定n支球队,第i支球队已经赢了wini场,输了losei场,接下来还有m场比赛,每个球队最终的收益为Cix2i+Diy2i,其中xi为最终的胜场,yi为最终的负场
求最小化收益

考虑一只球队,其收益与在接下来的比赛中的胜场数关系为:
0Ciwin2i+Di(di+losei)2
1Ci(wini+1)2+Di(di+losei1)2
2Ci(wini+2)2+Di(di+losei2)2

diCi(wini+di)2+Dilose2i

差分后可得:
赢第1Ci(2wini+1)Di[2(di+losei)1]
赢第2Ci(2wini+3)Di[2(di+losei)3]

赢第diCi[2wini+(2di1)]Di[2(di+losei)(2di1)]

容易发现差分后单调递增,故收益是关于胜场数的一个下凸函数,可以拆边做

于是我们将每支球队和每场比赛都变成一个点,建图跑费用流

源点向第i个点连di条边,流量为1,第j条边的费用为Ci[2wini+(2j1)]Di[2(di+losei)(2j1)]
每场比赛的双方向这场比赛连一条流量为1费用为0的边
每场比赛向汇点连一条流量为1费用为0的边

最小费用+ni=1[Ciwin2i+Di(di+losei)2]就是答案

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 6060#define S 0#define T (M-1)#define INF 0x3f3f3f3fusing namespace std;int n,m,ans;int win[M],lose[M],C[M],D[M],d[M];namespace Min_Cost_Max_Flow{    struct abcd{        int to,flow,cost,next;    }table[1001001];    int head[M],tot=1;    void Add(int x,int y,int f,int c)    {        table[++tot].to=y;        table[tot].flow=f;        table[tot].cost=c;        table[tot].next=head[x];        head[x]=tot;    }    void Link(int x,int y,int f,int c)    {        Add(x,y,f,c);        Add(y,x,0,-c);    }    bool Edmonds_Karp()    {        static int q[65540],cost[M],flow[M],from[M];        static unsigned short r,h;        static bool v[M];        int i;        memset(cost,0x3f,sizeof cost);        cost[S]=0;flow[S]=INF;q[++r]=S;        while(r!=h)        {            int x=q[++h];v[x]=false;            for(i=head[x];i;i=table[i].next)                if(table[i].flow&&cost[table[i].to]>cost[x]+table[i].cost)                {                    cost[table[i].to]=cost[x]+table[i].cost;                    flow[table[i].to]=min(flow[x],table[i].flow);                    from[table[i].to]=i;                    if(!v[table[i].to])                        v[table[i].to]=true,q[++r]=table[i].to;                }        }        if(cost[T]==0x3f3f3f3f) return false;        ans+=cost[T]*flow[T];        for(i=from[T];i;i=from[table[i^1].to])            table[i].flow-=flow[T],table[i^1].flow+=flow[T];        return true;    }}int main(){    using namespace Min_Cost_Max_Flow;    int i,j,x,y;    cin>>n>>m;    for(i=1;i<=n;i++)        scanf("%d%d%d%d",&win[i],&lose[i],&C[i],&D[i]);    for(i=1;i<=m;i++)    {        scanf("%d%d",&x,&y);        Link(x,n+i,1,0);        Link(y,n+i,1,0);        Link(n+i,T,1,0);        d[x]++;d[y]++;    }    for(i=1;i<=n;i++)    {        ans+=C[i]*win[i]*win[i]+D[i]*(d[i]+lose[i])*(d[i]+lose[i]);        for(j=1;j<=d[i];j++)            Link(S,i,1, C[i]*(2*win[i]+j*2-1)-D[i]*(2*(d[i]+lose[i])-j*2+1) );    }    while( Edmonds_Karp() );    cout<<ans<<endl;    return 0;}
0 0
原创粉丝点击