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

HINT

这题挺逗的。。。很好看出来是网络流
难点就在于你不能在跑网络流的时候把输赢的利益一起算上
所以做法很光(you)棍(xiu):每场比赛每队都算输,然后看看是哪个赢
根据它给的公式可以拆开,对于每一个球队,就建出每多赢一场的利益
它说明了它Ci>=Di,所以这肯定是递增的,就可以直接跑最小费用最大流了
代码如下:
//MT_LI
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define ll long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
    int f=1,x=0;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 stack[20];
inline void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
struct node{
    int x,y,c,d,next,other;
}a[21000];int len,last[11000];
void ins(int x,int y,int c,int d)
{
    a[++len]=(node){x,y,c,d,last[x],len+1};last[x]=len;
    a[++len]=(node){y,x,0,-d,last[y],len-1};last[y]=len;
}
int lose[5100],win[5100],c[5100],d[5100];
int n,m,st,ed;
int head,tail,list[110000];
int D[11000],ans;
int cc[11000],pre[11000];
bool v[11000];
bool spfa()
{
    for(int i=1;i<=ed;i++)D[i]=9999999;
    D[st]=0;
    memset(v,false,sizeof(v));v[st]=true;
    memset(cc,0,sizeof(cc));cc[st]=99999999;
    list[1]=st;head=1;tail=2;
    while(head!=tail)
    {
        int x=list[head];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(a[k].c>0&&D[y]>D[x]+a[k].d)
            {
                D[y]=D[x]+a[k].d;
                pre[y]=k;
                cc[y]=min(cc[x],a[k].c);
                if(v[y]==false)
                {
                    v[y]=true;
                    list[tail++]=y;
                }
            }
        }
        head++;
        v[x]=false;
    }
    if(D[ed]==9999999)return false;
    ans+=D[ed]*cc[ed];
    int x=ed;
    while(x!=0)
    {
        int k=pre[x];
        a[k].c-=cc[ed];a[a[k].other].c+=cc[ed];
        x=a[k].x;
    }
    return true;
}
int match[5100];
int main()
{
    n=read();m=read();
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)win[i]=read(),lose[i]=read(),c[i]=read(),d[i]=read();
    st=0;ed=n+m+1;
    for(int i=1;i<=m;i++)
    {
        ins(st,i,1,0);
        int x=read(),y=read();
        ins(i,x+m,1,0);ins(i,y+m,1,0);
        match[x]++,match[y]++;
    }
    for(int i=1;i<=n;i++)lose[i]+=match[i];
    int sum=0;
    for(int i=1;i<=n;i++)
        sum+=win[i]*win[i]*c[i]+lose[i]*lose[i]*d[i];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=match[i];j++)
        {
            ins(i+m,ed,1,2*c[i]*win[i]+c[i]+d[i]-2*d[i]*lose[i]);
            win[i]++,lose[i]--;
        }
    ans=0;
    while(spfa());
    printf("%d\n",sum+ans);
    return 0;
}

 

posted @ 2019-02-14 18:52  MT_LI  阅读(181)  评论(0编辑  收藏  举报