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 }
View Code

 

posted @ 2014-05-30 00:03  带鱼Yuiffy  阅读(239)  评论(0编辑  收藏  举报