zoukankan      html  css  js  c++  java
  • 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,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

    一个很巧妙的建图思想,因为对于胜负的影响我们不好表示,所以我们假定所有人都是输的,然后就可以只考虑一场胜利对其的影响

    我们先从源点像每个比赛建一条流量为1,费用为0的边(每场有且只有一个队伍胜利)

    然后从比赛像两支队伍i分别建一条流量为1,费用为0的边

    接下来考虑如何连向汇点

    首先我们肯定对于每只队伍都需要建基础分为权值的边

    然后每可以多赢一场我们就建一条权值为与上一次的差的边,这个我们是可以算出来的

    因为C>=D,所以权值是递增的,所以要是取边的话,一定优先取最靠前的边

    所以对于每个点取的边一定是连续的,这样就映射到了每个队胜利的场数

    然后这样就跑最小费用最大流就可以了

    #include<map>
    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define inf 1000000007
    #define ll long long
    #define N 100010
    inline int rd()
    {
        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;
    }
    int lj[N],fro[N],to[N],v[N],w[N],fa[N],cnt=1;
    inline void add(int a,int b,int c,int d){fro[++cnt]=lj[a];to[cnt]=b;v[cnt]=c;w[cnt]=d;fa[cnt]=a;lj[a]=cnt;}
    inline void ins(int a,int b,int c,int d){add(a,b,c,d);add(b,a,0,-d);}
    int T=6010;
    int dis[N],q[N],from[N];
    bool vs[N];
    bool spfa()
    {
        memset(dis,0x3f,sizeof(dis));
        int l=0,r=1,x;
        vs[0]=1;dis[0]=q[0]=0;
        while(l<r)
        {
            x=q[l++];vs[x]=0;
            for(int i=lj[x];i;i=fro[i])
                if(v[i]&&dis[to[i]]>dis[x]+w[i])
                {
                    dis[to[i]]=dis[x]+w[i];
                    from[to[i]]=i;
                    if(!vs[to[i]]){vs[to[i]]=1;q[r++]=to[i];}
                }
        }
        return dis[T]<inf;
    }
    int n,m,a[N],b[N],c[N],d[N],ji[N],ans;
    int main()
    {
        n=rd();m=rd();
        for(int i=1;i<=n;i++)
        {
            a[i]=rd();b[i]=rd();c[i]=rd();d[i]=rd();
        }
        int x,y;
        for(int i=1;i<=m;i++)
        {
            x=rd();y=rd();
            ins(0,i,1,0);
            ins(i,x+m,1,0);
            ins(i,y+m,1,0);
            ji[x]++;ji[y]++;
        }
        for(int i=1;i<=n;i++)
        {
            b[i]+=ji[i];
            ans+=a[i]*a[i]*c[i]+b[i]*b[i]*d[i];
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=ji[i];j++)
            {
                ins(i+m,T,1,2*c[i]*a[i]-2*d[i]*b[i]+c[i]+d[i]);
                a[i]++;b[i]--;
            }
        }
        int tp;
        while(spfa())
        {
            tp=inf;
            for(int i=from[T];i;i=from[fa[i]]) tp=min(tp,v[i]);
            for(int i=from[T];i;i=from[fa[i]]){v[i]-=tp;v[i^1]+=tp;}
            ans+=dis[T]*tp; 
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    系统分析师思维导图
    系统分析师案例分析知识点——虚拟内存篇
    系统分析师案例分析知识点——进程管理问题
    系统分析师案例分析知识点——进程同步问题
    200行代码实现RPC框架
    由vue3引起的一段值得记录经历
    PetaPoco在ASP.NET Core 2.2中使用注入方式访问数据库
    在.net core 中PetaPoco结合EntityFrameworkCore使用codefirst方法进行开发
    Quartz.NET的简单任务管理类
    System.Action的使用(lambda 表达式)
  • 原文地址:https://www.cnblogs.com/lkhll/p/7010705.html
Copyright © 2011-2022 走看看