zoukankan      html  css  js  c++  java
  • 【BZOJ-1449&2895】球队收益&球队预算 最小费用最大流

    1449: [JSOI2009]球队收益

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 648  Solved: 364
    [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

    2895: 球队预算

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 51  Solved: 50
    [Submit][Status][Discuss]

    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行每行两个整数s,t表示第s支队伍和第t支队伍之间将有一场比赛,注意两只队间可能有多场比赛。

    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
    Data Limit
    对于20%的数据2<=n<=10,0<=m<=20
    对于100%的数据2<=n<=5000,0<=m<=1000,0<=di<=ci<=10,0<=a[i],b[i]<=50.

    HINT

    Source

     

    Solution

    idea很好的建图,不能考虑直接建,而应该利用增量的思想

    个人的想法是这样的:

    源到各比赛连边,容量为1,费用为0

    建每个球队分成两个,由个比赛连向两只球队a,b,再由a连b',b连a',分别表示a赢了这场比赛或b赢了这场比赛

    然后由各个点i'连向汇容量为inf,费用为0

    然后预处理出来已比完的比赛胜负的价值,加上最小费用即可;

    思路是考虑一场比赛的胜负对于结果的贡献,从这场比赛结束后对结果的增量来考虑,但显然这种方法并不是很优,但理论上可A

    那么同样的思想,换一种方法建图

    不妨先假设后面的M场比赛中双方都是输家,这样我们只要在模型中表示一方成为赢家即可。

    此应该有一个初步的模型了:对于N支球队和M场比赛各建一个点,从源向每场比赛连流量1费用0的边,从比赛向参与这场比赛的两支队伍各连一条流量1费用0的边。剩下的就是队伍收益的费用表示了。

    多赢一场比赛产生的收益。即(C*(w+1)^2+D*(l-1)^2)-(C*w^2+D*l^2)=2w*C-2l*D+C+D。对于第i支队伍,假设后M场中i参加的有x场,那么最初w=win,l=lose+x,之后每赢一场w++,l--。我们从第i支队伍的点向汇连x条边,分别代表第i支队伍赢了j场比赛时相对赢j-1场时收益的增量。由于增量一定越来越大(平方嘛),所以流量最先流过的一定是费用较小的边,即j最小的边。

                                      -----by   huzecong

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<queue>
    using namespace std;
    int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0' || ch>'9') {if (ch=='-')f=-1; ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define maxn 5100+1100
    #define maxm 100100
    int n,m,ans,S,T,num[5010];
    struct Teamnode{int win,lose,C,D;}team[5010];
    struct Edgenode{int to,next,cap,cost,from;}edge[maxm];
    int head[maxn],cnt=1;
    void add(int u,int v,int w,int c) 
    {cnt++;edge[cnt].from=u;edge[cnt].to=v; 
    edge[cnt].next=head[u];head[u]=cnt; 
    edge[cnt].cost=c;edge[cnt].cap=w;} 
    void insert(int u,int v,int w,int c){add(u,v,w,c);add(v,u,0,-c);} 
    #define inf 0x7fffffff
    int q[maxn],h,t; int dis[maxn];bool mark[maxn];
    bool spfa()
    {
        memset(mark,0,sizeof(mark));
        for (int i=S; i<=T; i++) dis[i]=inf;
        h=0,t=1;
        q[0]=T; mark[T]=1; dis[T]=0;
        while (h<t)
            {
                int now=q[h++]; mark[now]=0;
                for (int i=head[now]; i; i=edge[i].next)
                    if (edge[i^1].cap && dis[now]+edge[i^1].cost<dis[edge[i].to])
                        {   
                            dis[edge[i].to]=dis[now]+edge[i^1].cost;
                            if (!mark[edge[i].to])
                                mark[edge[i].to]=1,q[t++]=edge[i].to;
                        }
            }
        return dis[S]!=inf;
    }
    int dfs(int loc,int low)
    {
        mark[loc]=1;
        if (loc==T) return low;
        int w,used=0;
        for (int i=head[loc]; i; i=edge[i].next)
            if (!mark[edge[i].to] && edge[i].cap && dis[edge[i].to]==dis[loc]-edge[i].cost)
                {
                    w=dfs(edge[i].to,min(low-used,edge[i].cap));
                    edge[i].cap-=w; edge[i^1].cap+=w;
                    ans+=w*edge[i].cost; used+=w;
                    if (used==low) return low;
                }
        return used;
    }
    int zkw()
    {
        int tmp=0;
        while (spfa())
            {
                mark[T]=1;
                while (mark[T])
                    {
                        memset(mark,0,sizeof(mark));
                        tmp+=dfs(S,inf);
                    }
            }
        return tmp;
    }
    int power(int x){return x*x;}
    void build()
    {
        S=0,T=n+m+1;
        for(int a,b,i=1; i<=m; i++)
            insert(S,i,1,0),
            a=read(),b=read(),
            insert(i,a+m,1,0),insert(i,b+m,1,0),
            num[a]++,num[b]++;
        for(int i=1; i<=n; i++)
            team[i].lose+=num[i];
        for(int i=1; i<=n; i++)
            ans+=power(team[i].win)*team[i].C+power(team[i].lose)*team[i].D;
        for(int i=1; i<=n; i++)
             for(int j=1;j<=num[i];j++)
                insert(i+m,T,1,2*team[i].C*team[i].win+team[i].C+team[i].D-2*team[i].D*team[i].lose),
                team[i].lose--,team[i].win++;
    }
    int main()
    {
        n=read(),m=read();
        for (int i=1; i<=n; i++)
            team[i].win=read(),team[i].lose=read(),
            team[i].C=read(),team[i].D=read();
        build();
        int Maxflow=zkw();
        printf("%d
    ",ans);
        return 0;
    }

    吐槽一句..增广的过程中,一开始使用STL中的queue然后莫名的WA了?手写了个q...怒A...跑得飞快

  • 相关阅读:
    ASCII码对照表
    createPopup 超链接
    说说回车键触发表单提交的问题
    linux下配java环境的小结
    spring bind checkbox 传递值问题
    用Common validator为springMVC做验证时遇到的一个问题小记
    [转载]对android LinearLayout中layout_weight属性使用初探
    linux下tomcat启动正常,但用http://22.22.33.33:8080却访问不了,防火墙的设置问题
    Java 遍历Map时 删除元素
    ftp用户登录时不能进自己的目录,被拒绝登录的解决方法
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5354337.html
Copyright © 2011-2022 走看看