zoukankan      html  css  js  c++  java
  • 【BZOJ1449】球队收益(JSOI2009)-费用流+拆边

    测试地址:球队收益
    做法:本题需要用到费用流+拆边。
    由于每场比赛只能有一个胜者,不难想到从每场比赛向比赛双方的队伍各连一条容量为1的边,并从源点向每场比赛连一条容量为1的边,这样每个队伍获得的流量就是它赢的场次了。我们先假设一支队伍所涉及的所有比赛它都输了,这种情况下会获得Cixi2+Di(yi+ti)2的收益,其中ti为这支队伍参加的场次,xi,yi就是它已经赢/输的场次。那么如果赢了a场,它就会获得比原来多Ci(2axia2)Di(2a(yi+ti)a2)的收益。我们发现这个很难表现成一条边的费用,于是我们把这条边拆成ti条容量为1的边,并使得它在选其中费用最少的a条边时,费用和为上面那个式子,我们可以构造出第a条边的费用应该为Ci(2(xi+a)1)Di(2(yi+tia)+1),即从赢a1场到赢a场新增的收益,显然这个东西是随着a的增大而增大的,所以满足上面的条件。那么我们把图建出来后,跑一遍最小费用最大流就可以求出最小的新增收益,最后加上原来我们假设已经获得的收益即可。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll inf=1000000000000000000ll;
    int n,m,S,T,first[6010]={0},tot=1,last[6010],laste[6010];
    ll x[5010],y[5010],c[5010],d[5010],deg[5010]={0};
    ll dis[6010],sum=0;
    bool vis[6010];
    queue<int> Q;
    struct edge
    {
        int v,next;
        ll f,c;
    }e[30010];
    
    void insert(int a,int b,ll f,ll c)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,e[tot].c=c,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,e[tot].c=-c,first[b]=tot;
    }
    
    void init()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld%lld%lld%lld",&x[i],&y[i],&c[i],&d[i]);
        S=n+m+1,T=n+m+2;
        for(int i=1;i<=m;i++)
        {
            int a,b;
            insert(S,i,1,0);
            scanf("%d%d",&a,&b);
            deg[a]++,deg[b]++;
            insert(i,m+a,1,0);
            insert(i,m+b,1,0);
        }
        for(int i=1;i<=n;i++)
        {
            sum+=c[i]*x[i]*x[i]+d[i]*(y[i]+deg[i])*(y[i]+deg[i]);
            for(ll j=1;j<=deg[i];j++)
                insert(m+i,T,1,c[i]*(2ll*(x[i]+j)-1ll)-d[i]*(2ll*(y[i]+deg[i]-j)+1));
        }
    }
    
    bool spfa()
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=T;i++)
            dis[i]=inf;
        dis[S]=0;
        vis[S]=1;
        Q.push(S);
        while(!Q.empty())
        {
            int v=Q.front();Q.pop();
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&dis[e[i].v]>dis[v]+e[i].c)
                {
                    last[e[i].v]=v;
                    laste[e[i].v]=i;
                    dis[e[i].v]=dis[v]+e[i].c;
                    if (!vis[e[i].v]) Q.push(e[i].v),vis[e[i].v]=1;
                }
            vis[v]=0;
        }
        return dis[T]!=inf;
    }
    
    void mincost()
    {
        ll minc=0;
        while(spfa())
        {
            int x=T;
            ll maxf=inf;
            while(x!=S)
            {
                maxf=min(maxf,e[laste[x]].f);
                x=last[x];
            }
            x=T;
            while(x!=S)
            {
                e[laste[x]].f-=maxf;
                e[laste[x]^1].f+=maxf;
                x=last[x];
            }
            minc+=maxf*dis[T];
        }
        printf("%lld",sum+minc);
    }
    
    int main()
    {
        init();
        mincost();
    
        return 0;
    }
  • 相关阅读:
    闲来无事,编写一个数据迁移小工具
    Moq基础
    探索逻辑事务 TransactionScope
    IntelliJ IDEA安装及jsp开发环境搭建
    数据结构整理(二) 树
    数据结构整理(一) 线性结构
    梳理delegate相关概念
    02_Android应用界面编程_01_视图(View)组件
    01_Android应用开发环境_05_签名android应用程序
    01_Android应用开发环境_04_Android常用开发工具的用法
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793430.html
Copyright © 2011-2022 走看看