首页 > 代码库 > 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 二分+最大流