您的位置:首页 > 运维架构

【POJ 2391 】Ombr 4000 ophobic Bovines 【floyd +二分+最大流】

2017-10-10 23:32 489 查看
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.

题意 : 有n个农场,第i个农场有a[i]头牛,如果下雨的话能够庇护b[i]头牛,农场之间有m条路,路是双向的边权为时间,只有当最后一头牛得到了庇护,才可以宣布此时的时间。

分析:如果算上每头牛来回转农场才到达庇护位置,这种就很难算,所以我们可以简化一下,我们可以预处理出来n头牛到另外n-1头牛的最短时间(因为每头牛无论怎么走都不会影响别的牛)。然后我们可以二分枚举这个宣布的时间,如果当前时间可以让所有的牛都得到庇护,那我们可以减少这个时间,不断下去,直到得到最小时间。

那么问题就转化为了,怎么快速判断,是否可以在当前时间限制下让所有的牛都得到庇护,这里可以建图,网络流,

超级源点S到n头牛都建边,容量为a[i]。

n头牛相对应的n个庇护点都与超级汇点T建边,容量为b[i].

然后n头牛分别到n个庇护点建边,如果所花费的时间小于当前限制时间,我们就建边,容量为INF,否则就不建边表示当前限制时间内无法到达。

然后判断T是否满流(即等于所有的牛数)

代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define  LL long long
#define fread() freopen("in.txt","r",stdin)
#define fwrite() freopen("out.txt","w",stdout)

const int MAXN = (200+10)*3;
const int MAXM = 200000+10;
const int mod = 1e9+7;
const LL inf = 1e16;

struct Edge {
int form,to,cap,flow,nexts;
}edge[MAXM];
int head[MAXN],top;
void init(){
memset(head,-1,sizeof(head));
top=0;
}
void addedge(int a,int b,int c){
Edge e={a,b,c,0,head[a]};
edge[top]=e;head[a]=top++;

Edge ee={b,a,0,0,head[b]};
edge[top]=ee;head[b]=top++;
}
int n,m;
int S,T;
LL mp[MAXN][MAXN];
int a[MAXN],b[MAXN];
int sum;
void floyd(){ //  求最短路
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
if(mp[i][k]==inf) continue;
for(int j=1;j<=n; j++)
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
}
}
void Read(){
sum=0;
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
sum+=a[i];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
if(i!=j) mp[i][j]=mp[j][i]=inf;
else mp[i][j]=0;
}

while(m--){
int x,y;LL c;
scanf("%d%d%lld",&x,&y,&c);
if(mp[x][y]>c){ //  注意有重边
mp[x][y]=c;
mp[y][x]=c;
}
}
floyd();
}
void getmap(LL mid){
S=0,T=n+n+1;
for(int i=1;i<=n;i++){
addedge(S,i,a[i]);
addedge(i+n,T,b[i]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(mp[i][j]<=mid){
addedge(i,j+n,1000000);
}
}
}
}
int vis[MAXN],dis[MAXN];
int cur[MAXN];
bool bfs(int st,int ed){
queue<int>Q;
memset(vis,0,sizeof(vis));
memset(dis,-1,sizeof(dis));
Q.push(st);vis[st]=1;dis[st]=1;
while(!Q.empty()){
int now=Q.front();Q.pop();
for(int i=head[now];i!=-1;i=edge[i].nexts){
Edge e=edge[i];
if(!vis[e.to]&&e.cap-e.flow>0){
vis[e.to]=1;
dis[e.to]=dis[now]+1;
if(e.to==ed) return 1;
Q.push(e.to);
}
}
}
return 0;
}
int dfs(int now,int a,int ed){
if(a==0||now==ed) return a;
int flow=0,f;
for(int &i=cur[now];i!=-1;i=edge[i].nexts){
Edge &e=edge[i];
if(dis[e.to]==dis[now]+1&&(f=dfs(e.to,min(e.cap-e.flow,a),ed))>0){
e.flow+=f;
flow+=f;
edge[i^1].flow-=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int max_flow(int st ,int ed){
int flow=0;
while(bfs(st,ed)){
memcpy(cur,head,sizeof(head));
flow+=dfs(st,inf,ed);
}
return flow;
}
void solve(){
LL l=0,r=inf;
LL ans=inf;//  注意这里要为ans赋值,因为极限情况下,下面的二分情况是不会对ans赋值的。
while(l<=r){
LL mid=(l+r)>>1;
init(); // *** 忘了init,找了半天bug
getmap(mid);
if(max_flow(S,T)==sum){
r=mid-1;  ans=mid;
}else l=mid+1;
}
if(ans == inf) puts("-1");
else printf("%lld\n",ans);
}

int main(){
//  fread();
//  fwrite();
while(scanf("%d%d",&n,&m)!=EOF){
Read();
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: