GDKOI2014 石油储备计划

Description

 

Input

Output

对于每组数据,输出一个整数,表示达到“平衡”状态所需的最小代价。
 

Sample Input

2

3

6 1 5

1 2 1

2 3 2

5

4 5 4 3 2

1 3 1

1 2 2

2 4 3

2 5 4

Sample Output

4

4

样例解释:

对于第一组数据,从城市1到城市2运输2桶石油,代价为1*2=2;从城市3往城市2运输1桶石油,代价为2*1=2。此时三个城市储备量都为4桶,该状态的平衡度为0。

对于第二组数据,从城市2到城市5运输1桶石油,代价为1*4=4;此时五个城市储备量为(4,4,4,3,3),该状态的非平衡度为1.2,是能达到的所有状态的最小值。
 

Data Constraint

对于20%的数据,N<=15

对于100%的数据,T<=10,N<=100,0<=si<=10000,1<=X,Y<=N,1<=Z<=10000。
 
首先容易得到结论:达到平衡状态时,每个点的油量要么为(sum/n),要么为(sum/n)+1,现在每个点有一个初始容量,在树上相邻的点可以转移石油。
我们可以据此建模
 
对于s向每个点,连一条上下界均为初始量的边,费用为0,表示最初容量,
对于每个点向t,连一条下界为(sum/n),上界为(sum/n)+1的边,表示经转移后的容量
对于原树上相邻的点,连一条下界为0,上界为正无穷,费用为距离的边,表示转移可用的路径
 
然后跑一遍最小费用可行流即可
 
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
typedef long long ll;

int g[2001],next[2011],y[2011],cost[2011],flow[2011];
int que[2000011],dis[2011],lb[2011],mn[2011],vis[2011];
int du[2011],a[2011];
int tt,tl,n,i,s,t,S,T,x,z,q,sum,dt,tj;
ll ans;

void star(int i,int j,int k,int l)
{
    tt++;
    next[tt]=g[i];
    g[i]=tt;
    y[tt]=j;
    flow[tt]=k;
    cost[tt]=l;
    tt++;
    next[tt]=g[j];
    g[j]=tt;
    y[tt]=i;
    flow[tt]=0;
    cost[tt]=-l;
}

void Spfa()//记录dis(最短路),min(最小流量),lb(连过的边,退流用)
{
    int l,r,x,j,k;
    memset(dis,127,sizeof(dis));
    memset(mn,0,sizeof(mn));
    memset(lb,0,sizeof(lb));
    tl++;
    l=r=1;
    que[l]=S;
    dis[S]=0;mn[S]=21474836;
    vis[S]=tl;
    while(l<=r){
        x=que[l];
        j=g[x];
        while(j!=0){
            if(flow[j]>0){
                k=y[j];
                if(dis[x]+cost[j]<dis[k]){
                    dis[k]=dis[x]+cost[j];
                    if(mn[x]<flow[j])mn[k]=mn[x];
                    else mn[k]=flow[j];
                    lb[k]=j;
                    if(vis[k]!=tl){
                        r++;
                        que[r]=k;
                        vis[k]=tl;
                    }
                }
            }
            j=next[j];
        }
        l++;
        vis[x]--;
    }
}

void Minflow()
{
    int x,j;
    ans=0;
    while(true){
        Spfa();
        if(dis[T]==2139062143)break;
        ans+=(ll)mn[T]*dis[T];
        x=T;
        while(x!=S){
            j=lb[x];
            flow[j]-=mn[T];
            flow[j^1]+=mn[T];
            x=y[j^1];
        }
    }
}

int main()
{
    scanf("%d",&dt);
    for(tj=1;tj<=dt;tj++){
        tt=1;
        memset(g,0,sizeof(g));
        memset(du,0,sizeof(du));
        scanf("%d",&n);
        sum=0;
        s=n+1;t=n+2;S=n+3;T=n+4;
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            du[i]+=a[i];
            du[s]-=a[i];
            sum+=a[i];
        }
        for(i=1;i<=n;i++){
            du[i]-=(sum/n);
            du[t]+=(sum/n);
            star(i,t,1,0);
        }
        for(i=1;i<n;i++){
            scanf("%d%d%d",&x,&z,&q);
            star(x,z,21474836,q);
            star(z,x,21474836,q);
        }
        star(t,s,21474836,0);
        for(i=1;i<=t;i++){
            if(du[i]>0)star(S,i,du[i],0);
            else star(i,T,-du[i],0);
        }
        Minflow();
        printf("%lld\n",ans);
    }
}

 

posted on 2015-05-07 08:58  razorjxt  阅读(250)  评论(0编辑  收藏  举报