首页 > 代码库 > poj 3228 Gold Transportation 二分+最大流

poj 3228 Gold Transportation 二分+最大流

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

题意:有n个城市,每个城市有一定量的金子,我们需要把所有的金子都存到城市中的仓库中,有一些道路连通这些城市,每条道路都有自己的花费,要求的是,把所有的金子都运到仓库中,所走的那些道路,其中花费的最大值最小是多少。

思路,二分答案,把花费比答案小的那些道路建成一个图,再建立一个源点和所有城市相连,流量是每个城市的金子数量,再建立一个汇点,连接所有的城市,流量是每个城市金子的最大存储量。再跑一遍最大流,如果流量等于所有的金子和,那么就可以,否则就不可以。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;


const int inf=1e9;
struct Side{
    int from,to,val;
}side1[20010];
struct Side2{
    int to,val,next;
}side2[40010];
int n,m;
int a[210],b[210];
int cnt,dis[210],gap[210];
int node[210],top;
int sum;


void addside(int a,int b,int c){
    side2[top]=(Side2){b,c,node[a]};
    node[a]=top++;
    side2[top]=(Side2){a,0,node[b]};
    node[b]=top++;
}


int getflow(int u,int f){
    if(u==n+1)
        return f;
    int ans=0;
    for(int i=node[u];i!=-1;i=side2[i].next){
        int to=side2[i].to,c=side2[i].val;
        if(dis[u]>dis[to]&&c){
            int x=getflow(to,min(f-ans,c));
            side2[i].val-=x;
            side2[i^1].val+=x;
            ans+=x;
            if(ans==f)  return ans;
        }
    }
    gap[dis[u]]--;
    if(gap[dis[u]]==0) dis[0]=cnt+2;
    dis[u]++;
    gap[dis[u]]++;
    return ans;
}


bool ok(int x){
    cnt=n+2;
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    memset(node,-1,sizeof(node));
    gap[0]=cnt;
    top=0;
    for(int i=1;i<=n;i++){
        addside(0,i,a[i]);
        addside(i,n+1,b[i]);
    }
    for(int i=0;i<m;i++) if(side1[i].val<=x){
        addside(side1[i].from,side1[i].to,inf);
        addside(side1[i].to,side1[i].from,inf);
    }
    int ans=0;
    while(dis[0]<cnt) ans+=getflow(0,inf);
    if(ans==sum)
        return 1;
    else  return 0;
}




int main()
{    
    while(cin>>n){
        sum=0;
        if(n==0) break;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        cin>>m;
        int x,y,z;
        int l=1e9,r=0,mid;
        for(int i=0;i<m;i++){
            scanf("%d %d %d",&x,&y,&z);
            side1[i]=(Side){x,y,z};
            l=min(l,z);
            r=max(r,z);
        }
        r++;
        int maxx=r;
        while(l!=r){
            mid=(l+r)/2;
            if(ok(mid))
                r=mid;
            else l=mid+1;
        }
        if(l==maxx)
            cout<<"No Solution"<<endl;
        else cout<<l<<endl;
    }
    return 0;
}


poj 3228 Gold Transportation 二分+最大流