Ombrophobic Bovines
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 15485 | Accepted: 3361 |
Description
FJ‘s cows really hate getting wet so much that the mere thought of getting caught in the rain makes them shake in their hooves. They have decided to put a rain siren on the farm to let them know when rain is approaching. They intend to create a rain evacuation
plan so that all the cows can get to shelter before the rain begins. Weather forecasting is not always correct, though. In order to minimize false alarms, they want to sound the siren as late as possible while still giving enough time for all the cows to get
to some shelter.
The farm has F (1 <= F <= 200) fields on which the cows graze. A set of P (1 <= P <= 1500) paths connects them. The paths are wide, so that any number of cows can traverse a path in either direction.
Some of the farm‘s fields have rain shelters under which the cows can shield themselves. These shelters are of limited size, so a single shelter might not be able to hold all the cows. Fields are small compared to the paths and require no time for cows to traverse.
Compute the minimum amount of time before rain starts that the siren must be sounded so that every cow can get to some shelter.
Input
* Line 1: Two space-separated integers: F and P
* Lines 2..F+1: Two space-separated integers that describe a field. The first integer (range: 0..1000) is the number of cows in that field. The second integer (range: 0..1000) is the number of cows the shelter in that field can hold. Line i+1 describes field
i.
* Lines F+2..F+P+1: Three space-separated integers that describe a path. The first and second integers (both range 1..F) tell the fields connected by the path. The third integer (range: 1..1,000,000,000) is how long any cow takes to traverse it.
Output
* Line 1: The minimum amount of time required for all cows to get under a shelter, presuming they plan their routes optimally. If it not possible for the all the cows to get under a shelter, output "-1".
Sample Input
3 4 7 2 0 4 2 6 1 2 40 3 2 70 2 3 90 1 3 120
Sample Output
110
Hint
OUTPUT DETAILS:
In 110 time units, two cows from field 1 can get under the shelter in that field, four cows from field 1 can get under the shelter in field 2, and one cow can get to field 3 and join the cows from that field under the shelter in field 3. Although there are
other plans that will get all the cows under a shelter, none will do it in fewer than 110 time units.
题意:有F块田,P条小路,点 i 处有 Ai 头牛,点 i 处的牛棚能容纳 Bi 头牛,求一个最短时 间 T 使得在 T 时间内所有的牛都能进到某一牛棚里去。
思路:显然建模是从源点S连接每一个牛棚,容量为当前牛数,再从每一个点连接一条边到汇点T,容量为每一个牛棚的容量,求最短时间采用的是二分搜索算法,核心是枚举可能的时间然后求一次最大流,如果最大流结果刚好等于总牛数,那么这个时间显然符合题意就将他记录下来,我们要找到最小的时间,故将时间向小的地方调整,如果不等于说明对于当前时间有牛不能走到汇点,故将二分向大的地方调整,就这样一直二分下去,这里需要进行拆点,将某一个点i拆成i和i+n,然后在每一次二分开始前重建网络,如果i和i+n之间的最短路径小于等于当前值,说明在当前时间下可以走到汇点,也就是说这个牛棚可以被装满,那就连接一条边从i->i+n容量为无穷大,建完图后求一次最大流,然后加入二分进行比较,得到的最终结果就是题目所求
PS:因为一个dp初始化的问题 wa了一晚上,sad
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <set> #include <queue> #include <map> using namespace std; const long long maxxint=1e16; const int inf=0x3f3f3f3f; int head[100010],num[1010],d[1010],cur[1010],pre[10010],q[1010]; long long dp[1010][1010],n,sum,cnt,s,t,nv; int maxint=inf; struct node { int u,v,cap; int next; } edge[10000010]; struct filed { int x,y; } p[1010]; void add(int u, int v, int cap) { edge[cnt].v=v; edge[cnt].cap=cap; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].cap=0; edge[cnt].next=head[v]; head[v]=cnt++; } void floyd() { int i, j, k; for(k=1; k<=n; k++) for(i=1; i<=n; i++) for(j=1; j<=n; j++) dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]); } void bfs() { memset(num,0,sizeof(num)); memset(d,-1,sizeof(d)); int f1=0,f2=0,i; q[f1++]=t; num[0]=1; d[t]=0; while(f1>=f2) { int u=q[f2++]; for(i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(d[v]!=-1) continue; d[v]=d[u]+1; num[d[v]]++; q[f1++]=v; } } } int isap() { memcpy(cur,head,sizeof(cur)); int flow=0,u=pre[s]=s,i; bfs(); while(d[s]<nv) { if(u==t) { int f=maxint, pos; for(i=s; i!=t; i=edge[cur[i]].v) { if(f>edge[cur[i]].cap) { f=edge[cur[i]].cap; pos=i; } } for(i=s; i!=t; i=edge[cur[i]].v) { edge[cur[i]].cap-=f; edge[cur[i]^1].cap+=f; } flow+=f; if(flow>=sum) return flow; u=pos; } for(i=cur[u]; i!=-1; i=edge[i].next) { if(d[edge[i].v]+1==d[u]&&edge[i].cap) break; } if(i!=-1) { cur[u]=i; pre[edge[i].v]=u; u=edge[i].v; } else { if((--num[d[u]])==0) break; int mind=nv; for(i=head[u]; i!=-1; i=edge[i].next) { if(mind>d[edge[i].v]&&edge[i].cap) { mind=d[edge[i].v]; cur[u]=i; } } d[u]=mind+1; num[d[u]]++; u=pre[u]; } } return flow; } int main() { long long m,i,j; long long a,b,c; scanf("%lld %lld",&n,&m); sum=0; for(i=0; i<=n; i++) for(j=0; j<=n; j++) { if(i==j) dp[i][j]=0; else dp[i][j]=maxxint;//因为这个地方初始化的是inf 导致wa了一晚上,应该初始化为maxxint,因为在下面二分的时候的上界是2^11 } for(i=1; i<=n; i++) { scanf("%d %d",&p[i].x,&p[i].y); sum+=p[i].x; } while(m--) { scanf("%lld %lld %lld",&a,&b,&c); if(dp[a][b]>c) { dp[a][b]=dp[b][a]=c; } } floyd(); int x; long long low=1,high=2000000000000,mid,ans=-1; while(low<=high) { mid=(high+low)/2; cnt=0; s=0; t=2*n+1; nv=t+1; memset(head,-1,sizeof(head)); for(i=1; i<=n; i++) { add(s,i,p[i].x); add(i+n,t,p[i].y); } for(i=1; i<=n; i++) for(j=1; j<=n; j++) { if(dp[i][j]<=mid) add(i,j+n,inf); } x=isap(); if(x>=sum) { ans=mid; high=mid-1; } else low=mid+1; } printf("%lld\n",ans); return 0; }