Gold Transportation(二分+最大流)

原题: http://poj.org/problem?id=3228

题意:

有n个点,m条边,每个点有一个存储量和货物量,求运输的最长路段(路径中最长的那条)的最小值,使所有货物可以存放。

解析:

首先二分答案,小于等于答案的边直接连上,流量设inf
然后源点到各个点,流量设为货物量
所有点到汇点,流量设为存储量

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=1001,M=100001;

int head[N],nex[M],to[M],val[M],now;
void add(int a,int b,int v){
    to[++now]=b;val[now]=v;nex[now]=head[a];head[a]=now;
    to[++now]=a;val[now]=0;nex[now]=head[b];head[b]=now;
}

//*********************

int sp,ep,d[N];

int bfs(){
    queue<int>Q;
    memset(d,-1,sizeof(d));
    d[sp]=0;
    Q.push(sp);
    while(!Q.empty()){
        int p=Q.front();Q.pop();
        for(int i=head[p];~i;i=nex[i]){
            int u=to[i];
            if(d[u]==-1&&val[i]>0){
                d[u]=d[p]+1;
                Q.push(u);
            }
        }
    }
    return d[ep]!=-1;
}

int dfs(int p,int v){
    int r=0;
    if(p==ep)return v;
    for(int i=head[p];(~i)&&r<v;i=nex[i]){
        int u=to[i];
        if(val[i]>0&&d[u]==d[p]+1){
            int x=dfs(u,min(val[i],v-r));
            r+=x;
            val[i]-=x;
            val[i^1]+=x;
        }
    }
    if(!r)d[p]=-2;
    return r;
}

int dinic(){
    int ans=0,t;
    while(bfs()){
        while(t=dfs(sp,inf))ans+=t;
    }
    return ans;
}

//***********************

void init(){
    now=-1;//要求第一条边为0
    memset(head,-1,sizeof(head));
}

int n,m,sum;
int a[M],b[M],v[M];
int s[N],g[N];

int judge(int limit){
    init();
    sp=0,ep=201;
    for(int i=1;i<=m;i++){
        if(v[i]<=limit){
            add(a[i],b[i],inf);
            add(b[i],a[i],inf);
        }
    }
    for(int i=1;i<=n;i++){
        if(s[i]){
            add(0,i,s[i]);
        }
        if(g[i]){
            add(i,201,g[i]);
        }
    }
    int ans=dinic();
    if(ans==sum)return 1;
    return 0;
}

int main(){while(scanf("%d",&n)!=EOF){
    if(!n)break;
    sum=0;
    for(int i=1;i<=n;i++)scanf("%d",s+i),sum+=s[i];
    for(int i=1;i<=n;i++)scanf("%d",g+i);

    scanf("%d",&m);
    int l=0,r=1e4;
    for(int i=1;i<=m;i++)scanf("%d%d%d",a+i,b+i,v+i);
    if(!judge(1e4)){printf("No Solution\n");continue;}
    if(judge(0)){printf("%d\n",0);continue;}
    while(r-l>1){
        int mid=l+r>>1;
        if(judge(mid))r=mid;
        else l=mid;
    }
    printf("%d\n",r);
}}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/86595016
今日推荐