POJ 2391 Ombrophobic Bovines【二分+最大流】
题意: 已知有 N 个牛棚,且每个牛棚在一开始的时候有一定数量的牛,每个牛棚可以用来让牛避雨,但容量都有一定的限制,知道了一些牛棚之间的道路长度,
问使得下雨时使所有牛都可以找到地方躲雨,且要使得所有牛中走过的路中的最大值尽可能小,并求出该最大值
分析: 建图:
将每个牛棚拆成两个点v,v`
建立一个源点 s =0 , 在 s 和每个点 i 之间连一条容量大小为该牛棚初始牛数量的边,
建立一个汇点 t =2*n+1 在 每个点 i+n 和 t 之间连一条容量大小为该牛棚容量的边。
如果点 u 和 v 满足条件,就在 u 和 v +n ,v 和 u+n之间连一条容量大小为 INF 的边。
如果最大流 = 牛的数量 ,即说明该情况符合。
#include<stdio.h> #include<string.h> #include<stdlib.h> #define clr(x)memset(x,0,sizeof(x)) #define INF 0x1f1f1f1f #define min(a,b)(a)<(b)?(a):(b) int v[405][405]; int gap[405]; int dis[405]; int c[405][405]; void init(int s,int u,int n) { int v,x,front=0,rear=0; int q[405]; clr(gap); memset(dis,0xff,sizeof(dis)); q[rear++]=u; dis[u]=0; while(front<rear) { x=q[front++]; gap[dis[x]]++; for(v=0;v<=n;v++) if(dis[v]==-1&&c[v][x]>0) { dis[v]=dis[x]+1; q[rear++]=v; } } } int sap(int s,int u,int n) { init(s,u,n); int flag,flow=0,top=s,i,j,k; int pre[405]; int low[405]; while(dis[s]<=n) { flag=0; low[s]=INF; for(i=0;i<=n;i++) if(c[top][i]>0&&dis[top]==dis[i]+1&&dis[i]>=0) { flag=1; break; } if(flag) { low[i]=c[top][i]; low[i]=min(low[i],low[top]); pre[i]=top; top=i; if(top==u) { flow+=low[u]; j=top; while(j!=s) { k=pre[j]; c[k][j]-=low[u]; c[j][k]+=low[u]; j=k; } top=s; clr(low); } } else { int dmin=n; for(j=0;j<=n;j++) if(c[top][j]>0&&dis[j]+1<dmin&&dis[j]>=0) dmin=dis[j]+1; gap[dis[top]]--; if(gap[dis[top]]==0) break; gap[dmin]++; dis[top]=dmin; if(top!=s) top=pre[top]; } } return flow; } long long g[405][405]; int st[202]; int ho[202]; int ok(long long ti,int s,int n,int tot) { int i,j,flow; clr(c); for(i=1;i<=n;i++) { c[s][i]=st[i]; c[i+n][n*2+1]=ho[i]; } for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(g[i][j]!=-1&&g[i][j]<=ti) { c[i][j+n]=INF; c[j][i+n]=INF; } flow=sap(s,2*n+1,2*n+1); if(flow==tot) return 1; return 0; } int main() { int s,t,n,m,i,j,k,a,b,t1,t2; long long low,high,mid,res,w; while(scanf("%d%d",&n,&m)!=EOF) { s=0; t1=t2=0; high=0; for(i=1;i<=n;i++) { scanf("%d%d",&st[i],&ho[i]); t1+=st[i]; t2+=ho[i]; } memset(g,-1,sizeof(g)); while(m--) { scanf("%d%d%lld",&a,&b,&w); if(g[a][b]==-1||w<g[a][b]) { //high+=w; g[a][b]=g[b][a]=w; } } if(t1>t2) { printf("-1\n"); continue; } for(k=1;k<=n;k++) for(i=1;i<=n;i++) if(g[i][k]!=-1) for(j=1;j<=n;j++) if(g[k][j]!=-1&&(g[i][k]+g[k][j]<g[i][j]||g[i][j]==-1)) g[i][j]=g[i][k]+g[k][j]; for(i=1;i<=n;i++) g[i][i]=0; low=0; high=0; for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(g[i][j]>high) high=g[i][j]; res=-1; while(low<=high) { mid=(low+high)>>1; if(ok(mid,s,n,t1)) { res=mid; high=mid-1; } else low=mid+1; } printf("%lld\n",res); } return 0; }