poj2391 Ombrophobic Bovines 题解
http://poj.org/problem?id=2391
floyd+网络流+二分
题意:有一个有向图,里面每个点有ai头牛,快下雨了牛要躲进雨棚里,每个点有bi个雨棚,每个雨棚只能躲1头牛。牛可以通过点之间的边移动来躲到其他的点的雨棚,路很宽一次可以走无数头牛,路的权是牛走过这条路要的时间。求最短需要多少时间所有牛都躲到雨棚下。
题解:
先floyd求出每个点到每个点的最短时间!然后二分答案,也就是二分牛躲完的时间,然后大于这个时间的路都封了,建个碉图,每个点分成两个点A和B,起点连接到所有的A,流量为牛数,所有的点B连接到终点,流量为棚数,一些A连接到一些B,流量为无限,代表牛的移动。二分+网络流,啪啪啪就过了。这是我做的第一个二分+网络流的题,好激动口牙!
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 const long long inf=0x7fffffffffffLL; 7 const int MAXN=444; 8 long long a[MAXN][MAXN]; 9 long long b[MAXN][MAXN]; 10 long long d[MAXN][MAXN]; 11 int m,n; 12 ll c[MAXN][MAXN]; 13 ll D[MAXN],h[MAXN],g[MAXN]; 14 bool found; 15 ll augc,flow; 16 int st,ed,N; 17 ll sum; 18 19 void floyd() 20 { 21 int i,j,k; 22 memcpy(d,b,sizeof(b)); 23 for(k=1;k<=n;k++) 24 for(i=1;i<=n;i++) 25 for(j=1;j<=n;j++) 26 if(d[i][k]+d[k][j]<d[i][j]) 27 d[i][j]=d[i][k]+d[k][j]; 28 } 29 30 void aug(const int m) 31 { 32 int i,augco=augc,mini,minh=N-1; 33 if (m==ed)//如果当前结点为汇点 34 { 35 found=true; 36 flow+=augc; //增加流量 37 return; 38 } 39 for (i=D[m]; i<=N; i++)//寻找容许边 40 if (c[m][i]>0 && h[i]+1==h[m])//如果残留容量大于0,如果是容许边 41 { 42 if (c[m][i]<augc) augc=c[m][i];//如果容许边流量小于当前增广路流量 则更新增广路流量 43 D[m]=i; //把i定为当前弧 44 aug(i); //递归 45 if (h[1]>=N) return; //GAP 如果源点距离标号大于n 则停止算法 46 if (found) break; //如果找到汇点 则退出寻找 47 augc=augco;//没找到就还原当前的流 48 } 49 if (!found) //重标号 50 { 51 for (i=1; i<=N; i++) //找那个标号,这里不能用d[m]开始,不然会蛋疼 52 if (c[m][i]>0 && h[i]<minh) 53 { 54 minh=h[i]; 55 mini=i; 56 } 57 g[h[m]]--; //GAP 距离为 58 if (g[h[m]]==0) h[1]=N; //GAP 59 h[m]=minh+1; 60 D[m]=mini; 61 g[h[m]]++; //GAP 62 } 63 else 64 {//修改残量 65 c[m][i]-=augc; 66 c[i][m]+=augc; 67 } 68 } 69 70 bool farm(ll time) 71 { 72 int i,j; 73 //cout<<"farm"<<time<<endl; 74 memcpy(c, a, sizeof(a)); 75 for(i=1;i<=n;i++) 76 for(j=1;j<=n;j++) 77 if(d[i][j]<=time) c[i+1][j+1+n]=inf; 78 else c[i+1][j+1+n]=0; 79 N=ed; 80 // for(i=1;i<=N;i++) 81 // { 82 // for(j=1;j<=N;j++) 83 // cout<<c[i][j]<<' '; 84 // cout<<endl; 85 // } 86 memset(h,0,sizeof(h)); 87 memset(g,0,sizeof(g)); 88 g[0]=N; 89 flow=0; 90 for(i=1; i<=N; i++) 91 D[i]=1;//当前弧初始化 92 while(h[1]<N) 93 { 94 augc=inf;//初始化增广路容量为正无穷大 95 found=false; 96 aug(1);//从源点开始找 97 } 98 if(flow==sum) return true; 99 else return false; 100 } 101 102 int main() 103 { 104 int i,j,k; 105 ll x,y,z; 106 while(scanf("%d%d",&n,&m)!=EOF) 107 { 108 sum=0; 109 memset(a,0,sizeof(a)); 110 st=1;ed=n+n+2; 111 for(i=2;i<=n+1;i++) 112 { 113 scanf("%lld%lld",&x,&y); 114 sum+=x; 115 a[1][i]+=x; 116 a[i+n][ed]+=y; 117 } 118 for(i=1;i<=n;i++) 119 for(j=1;j<=n;j++) 120 b[i][j]=inf; 121 for(i=1;i<=n;i++) 122 b[i][i]=0; 123 for(i=1;i<=m;i++) 124 { 125 scanf("%lld%lld%lld",&x,&y,&z); 126 b[x][y]=min(b[x][y],z); 127 b[y][x]=b[x][y]; 128 } 129 floyd(); 130 ll l=inf,r=-1; 131 for(i=1;i<=n;i++) 132 for(j=1;j<=n;j++) 133 { 134 l=min(l,d[i][j]); 135 r=max(r,d[i][j]); 136 } 137 r=min(inf-1,r); 138 if (!farm(r)) 139 { 140 printf("-1\n"); 141 continue; 142 } 143 ll mid=(l+r)/2,pl=-1,pr=-1; 144 while(l!=pl || r!=pr) 145 { 146 pl=l;pr=r; 147 if(farm(mid)) r=mid; 148 else l=mid; 149 mid=(l+r)/2; 150 //cout<<l<<','<<r<<','<<mid<<endl; 151 } 152 printf("%lld\n",r); 153 } 154 return 0; 155 }