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?lose2i

差分后可得:

赢第1场 Ci?(2?wini+1)?Di?[2?(di+losei)?1]

赢第2场 Ci?(2?wini+3)?Di?[2?(di+losei)?3]

赢第di场 Ci?[2?wini+(2?di?1)]?Di?[2?(di+losei)?(2?di?1)]

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

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

源点向第i个点连di条边,流量为1,第j条边的费用为Ci?[2?wini+(2?j?1)]?Di?[2?(di+losei)?(2?j?1)]

每场比赛的双方向这场比赛连一条流量为1费用为0的边

每场比赛向汇点连一条流量为1费用为0的边

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

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 6060
#define S 0
#define T (M-1)
#define INF 0x3f3f3f3f
using 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;
}
时间: 2024-11-10 08:02:51

BZOJ 1449 JSOI2009 球队收益 费用流的相关文章

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

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

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

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 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 [思路] 费用拆分,

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]球队收益

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 二次费用流模板题.

BZOJ 2668 交换棋子(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668 题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与m[i,j]次交换. 思路: 我们将1看做要移动的数字,将0看做空白.那么若1在始末状态个数不同则无解:如某个格子始末状态均有1则这个格子的1对结果无影响,可以将其都置为0.将每个格子拆为为个点p0,p1,p2: (1)若格子初始为1,则连边:<s,p0,1,0>

BZOJ 3171 循环格(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3171 题意: 思路:若能构成循环,则每个格子的入度出度 均为1.因此将每个点拆成两个点x1,x2,分别作为出点和入点.出点向周围四个点的入点连边,流1,费用视该格子的字母而定.该格子的字母正好是这个方 向则费用为0否则为1.原点S向每个出点连边,流量1费用0:每个入点向汇点连边,流量1费用0.求最小费用最大流即可. struct node { int u,v,next,cost,cap

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

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]*