bzoj1449/2895: [JSOI2009]球队收益(最小费用最大流)

www.cnblogs.com/shaokele/


bzoj1449: [JSOI2009]球队收益##

  Time Limit: 5 Sec
  Memory Limit: 64 MB

Description###

  p1
 

Input###

  p2
 

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

  p3
  

题目地址:  bzoj1449: [JSOI2009]球队收益

题目大意:   题目很简洁了:)####

  

题解:   hzwer

  最小费用最大流
  
  首先假设每场比赛两队都是负......算出初始收益
  
  然后考虑每次比赛,其中一队为胜
  
  从源向每场比赛连流量1费用0的边,从比赛向这场比赛的两支队都连一条流量1费用0的边
  
  然后考虑费用的增量:多赢一场比赛产生的收益。即 $$(C(w+1)2+D*(l-1)2)-(Cw2+D*l2)=2wC-2lD+C+D$$
  
  对于某支球队,假设后M场中其参加x场,那么最初 (w=win,l=lose+x) ,之后每赢一场 (w++,l--)
  
  我们从它向汇连 (x) 条边,分别代表其赢了 (j) 场比赛时相对赢 (j-1) 场时收益的增量。由于增量递增,所以可以保证正确性。
  
  答案为所有队伍最初收益+最小费用最大流费用。
  


AC代码

#include <cstdio>
#include <algorithm>
using namespace std;
const int N=5005,M=1005,inf=1e9;
int n,m,S,T,cnt,ans;
int last[N+M],q[N+M],d[N+M],from[N+M];
int win[N],lose[N],C[N],D[N],s[N];
bool inq[N+M];
struct edge{
    int from,to,v,c,next;
}e[100005];
void insert(int u,int v,int w,int c){
    e[++cnt]=(edge){u,v,w,c,last[u]};last[u]=cnt;
    e[++cnt]=(edge){v,u,0,-c,last[v]};last[v]=cnt;
}
bool spfa(){
    for(int i=S;i<=T;i++)d[i]=inf;
    int l=0,r=1;q[0]=S;
    d[S]=0;inq[S]=1;
    while(l!=r){
        int u=q[l++];if(l==T)l=0;
        for(int i=last[u];i;i=e[i].next)
            if(e[i].v && d[e[i].to]>d[u]+e[i].c){
                d[e[i].to]=d[u]+e[i].c;
                from[e[i].to]=i;
                if(!inq[e[i].to]){
                    inq[e[i].to]=1;
                    q[r++]=e[i].to;
                    if(r==T)r=0;
                }
            }
        inq[u]=0;
    }
    if(d[T]==inf)return 0;
    return 1;
}
void mcf(){
    int x=inf;
    for(int i=from[T];i;i=from[e[i].from])
        x=min(x,e[i].v);
    for(int i=from[T];i;i=from[e[i].from]){
        e[i].v-=x;
        e[i^1].v+=x;
        ans+=e[i].c*x;
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d%d",&win[i],&lose[i],&C[i],&D[i]);
    S=0;T=n+m+1;cnt=1;
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        insert(S,i,1,0);
        insert(i,m+u,1,0);
        insert(i,m+v,1,0);
        s[u]++;s[v]++;
    }
    for(int i=1;i<=n;i++){
        lose[i]+=s[i];
        ans+=win[i]*win[i]*C[i]+lose[i]*lose[i]*D[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=s[i];j++){
            insert(m+i,T,1,2*C[i]*win[i]+C[i]+D[i]-2*D[i]*lose[i]);
            lose[i]--;win[i]++;
        }
    while(spfa())mcf();
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/shaokele/p/9118368.html