Poj 2391 Ombrophobic Bovines【二分+最大流Dinic】

Ombrophobic Bovines

Time Limit: 1000MS

 

Memory Limit: 65536K

Total Submissions: 18040

 

Accepted: 3921

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.

Source

USACO 2005 March Gold

 

题目大意:

有F个点,P条无向边,给你每个点有多少头牛,这个点最多能够存多少头牛,然后给你P条无向边的信息,u,v以及走过这条边需要耗费的时间w。牛可以在无向边上随意走动,求一个最短时间,使得每个点都没有多余的牛。


分析样例:

点1有7头牛,能够存两头牛,点2没有牛可以存4头牛,点3有2头牛可以存六头牛,那么我们从点1派出5头牛,全部走到2,用时40,然后在点2留下四头牛,然后剩下最后一头牛走到点3,最终耗时110(题目让你找的这个最短时间不是路径时间和,而是最后一头牛安置完毕之后一共用时多少)


思路:.


1、首先,我们要尽量短的时间,从样例输入来看,是一个有重边的无向图,我们用map【i】【j】邻接矩阵来存图,跑一遍最短路Floyd,求出两点间最短路。


2、对于时间来讲,时间越长,能够找到正确位子的牛就越多,所以我们二分枚举当前值mid,作为一个解,去进行判断。如果当前值可行,那么记录这个值,继续二分,直到不能二分为止,输出最后一个可行解。


3、那么对于当前值mid,建图:

①建立源点S,将其连入各个点(1-n),其权值设定为这个点有多少头牛。

②建立汇点T,将各个点的拆点(n+1,2*n)连入汇点T,其权值设定为这个点能够存多少头牛。

③遍历Floyd之后的邻接矩阵,如果对应map【i】【j】<=mid,那么建立有向边(i,j+n),其权值设定为INF。


4、建好图之后跑最大流 ,如果maxflow==sum(sum表示所有牛的和)那么当前mid值就是一个可行解。


5、注意数据范围,注意初始化,__int64是必不可少的。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
#define ll __int64
struct node
{
    int from;
    int to;
    int w;
    int next;
}e[200*200*10];
int n,m,ss,tt,cont,sum;
ll map[250][250];
int divv[250*5];
int head[250*5];
int cur[250*5];
int have[20000];
int hold[20000];
void add(int from,int to,int w)
{
    e[cont].to=to;
    e[cont].w=w;
    e[cont].next=head[from];
    head[from]=cont++;
}
void getmap(ll mid)
{
    ss=n*2+1;
    tt=ss+1;
    cont=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        add(ss,i,have[i]);
        add(i,ss,0);
        add(i+n,tt,hold[i]);
        add(tt,i+n,0);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(map[i][j]<=mid)
            {
                add(i,j+n,0x3f3f3f3f);
                add(j+n,i,0);
            }
        }
    }
}
int makedivv()
{
    queue<int >s;
    memset(divv,0,sizeof(divv));
    divv[ss]=1;
    s.push(ss);
    while(!s.empty())
    {
        int u=s.front();
        if(u==tt)return 1;
        s.pop();
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            if(w&&divv[v]==0)
            {
                divv[v]=divv[u]+1;
                s.push(v);
            }
        }
    }
    return 0;
}
int Dfs(int u,int maxflow,int tt)
{
    if(u==tt)return maxflow;
    int ret=0;
    for(int &i=cur[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        int w=e[i].w;
        if(w&&divv[v]==divv[u]+1)
        {
            int f=Dfs(v,min(maxflow-ret,w),tt);
            e[i].w-=f;
            e[i^1].w+=f;
            ret+=f;
            if(ret==maxflow)return ret;
        }
    }
    return ret;
}
int Dinic(ll mid)
{
    getmap(mid);
    int ans=0;
    while(makedivv()==1)
    {
        memcpy(cur,head,sizeof(head));
        ans+=Dfs(ss,0x3f3f3f3f,tt);
    }
    if(ans==sum)return 1;
    else return 0;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        sum=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                map[i][j]=1LL<<60;
            }
            map[i][i]=0;
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&have[i],&hold[i]);
            sum+=have[i];
        }
        for(int i=0;i<m;i++)
        {
            int x,y;
            ll w;
            scanf("%d%d%lld",&x,&y,&w);
            if(map[x][y]>w)
            {
                map[x][y]=map[y][x]=w;
            }
        }
        ll maxn=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                for(int k=1;k<=n;k++)
                {
                    map[j][k]=min(map[j][k],map[j][i]+map[i][k]);
                    if(map[j][k]!=(1LL<<60))
                    maxn=max(maxn,map[j][k]);
                }
            }
        }
        ll l=0;
        ll r=maxn+5;
        ll mid;
        ll ans=-1;
        while(r>=l)
        {
            mid=(l+r)/2;
            if(Dinic(mid)==1)
            {
                r=mid-1;
                ans=mid;
            }
            else
            {
                l=mid+1;
            }
        }
        printf("%lld\n",ans);
    }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值