poj2391 二分+floyd+dinic

Ombrophobic Bovines
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 15586 Accepted: 3388

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.

题意:有若干个地点,每个点上有一定数目的牛和一个牛棚,牛棚有最大容量。再告诉地点之间一些道路(无向的),道路拥有一个权值,表示走这条路需要耗费这么多时间,

注意一下如果输入中含有多个i j val1,i j val2,j i val3...应取最小那条边。题目问最少需要多少时间,牛能够全部躲进牛棚。

首先这种最优性问题是很难的,我们不妨二分时间,将其变成判定性问题。

首先预处理i,j之间的最短路,用floyd即可。

然后需要拆点,将点i拆成两个点i',i'',从源点连向i',权值为num[i](牛的数量),i''连向汇点,权值为stay[i](牛棚的容量),然后是i'连向i'',权值为无穷大(这就是所谓的拆点) ,然后枚举两点i,j,如果距离小于等于二分的时间,则表示两地可在这段时间到达,于是i'连向j'',权值为无穷大。

这里唯一的疑问是会不会走了多段,然后时间叠加超过了二分的时间呢?

答案是不会,因为i到k如果经过j的话,显然要i'->j'->k'',而i'->j'这条边是不存在的,只存在i'->j'',其实既然已经是最短路了,dist[i][k]自然可能经过j,但我们让流过j的流量为0,这相当于不经过j,直接由i到达k。也就是可以把一段复杂的路径拆分成若干假想的直达过程,这也就是拆点的精髓所在。

被坑了一把,时间可以爆int的。。。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 510
#define ll long long
using namespace std;

const int inf=0x3f3f3f3f;
const ll INF=1LL<<60;
int stay[Maxn],num[Maxn];
ll dist[Maxn][Maxn];
struct line{
    int to,next,cap;
}p[Maxn*Maxn];
int head[Maxn];
int q[Maxn];
int d[Maxn];
int tot;
int src,t;
int n,m;
void addedge(int a,int b,int c){
    p[tot].to=b;
    p[tot].next=head[a];
    p[tot].cap=c;
    head[a]=tot++;
}
void insert(int a,int b,int c){
    addedge(a,b,c);
    addedge(b,a,0);
}
bool bfs(){
    memset(d,-1,sizeof d);
    int s=0,e=-1;
    q[++e]=src;
    d[src]=0;
    while(s<=e){
        int u=q[s++];
        for(int i=head[u];i!=-1;i=p[i].next){
            int v=p[i].to;
            if(d[v]==-1&&p[i].cap){
                d[v]=d[u]+1;
                q[++e]=v;
            }
        }
    }
    return d[t]!=-1;
}
int dfs(int u,int alpha){
    if(u==t) return alpha;
    int w,used=0;
    for(int i=head[u];i!=-1&&used<alpha;i=p[i].next){
        int v=p[i].to;
        if(p[i].cap&&d[v]==d[u]+1){
            w=dfs(v,min(alpha-used,p[i].cap));
            used+=w;
            p[i].cap-=w;
            p[i^1].cap+=w;
        }
    }
    if(!used) d[u]=-1;
    return used;
}
int dinic(){
    int ans=0;
    src=0,t=500;
    while(bfs())
        ans+=dfs(src,inf);
    return ans;
}
void floyd(){
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
}
void add(ll T){
    memset(head,-1,sizeof head);
    tot=0;
    for(int i=1;i<=n;i++){
        insert(0,i,num[i]);
        insert(i,i+210,inf);
        insert(i+210,500,stay[i]);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j&&dist[i][j]<=T)
                insert(i,j+210,inf);
}
int main()
{
    int a,b;
    ll c;
    while(cin>>n>>m){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dist[i][j]=INF;
        for(int i=1;i<=n;i++) dist[i][i]=0;
        int res=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d",num+i,stay+i);
            res+=num[i];
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%lld",&a,&b,&c);
            dist[a][b]=min(dist[a][b],c);
            dist[b][a]=min(dist[b][a],c);
        }
        floyd();
        /*for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                printf("%lld ",dist[i][j]);
            puts("");
        }*/
        ll l=0,r=INF;
        while(l<r){
            ll mid=l+r>>1;
            add(mid);
            if(dinic()<res) l=mid+1;
            else r=mid;
        }
        if(l==INF) l=-1;
        printf("%lld\n",l);
    }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值