POJ 2391 Ombrophobic Bovines 二分拆点最大流+floyd(高精度)

Ombrophobic Bovines
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 13321 Accepted: 2930

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


有n个牛棚,每个牛棚旁边都有一定数量的牛,每个牛棚也有能够容纳的牛的数量,某些牛棚与牛棚之间有些路,牛可以花费一些时间到达,而且任何路都能容纳无限多的牛经过。让你求最短的时间内使得所有的牛都到牛棚里去。(图论的题怎么都与牛有关?)
此题建图的话要将牛棚拆点,拆点的牛棚之间的容量为inf,源点与每个牛棚相连,容量为此牛棚旁边的牛的数量,然后拆点后的牛棚与汇点相连,容量为牛棚容纳的数量。拆点是为了在二分的时候对流进行限制。然后利用floyd算法求出没两个牛棚之间花费的最少时间,然后二分求解最短时间,将每次两个牛棚之间时间小于二分的时间连边,容量为inf,因为道路可以容纳任意多的牛经过。
此外此题一定要注意高精度,路之间的距离最大是1000000000,而最多有200个牛棚,所以初始化两点间距离的时候最小应该是1000000000*200=200000000000。
//2436K	219MS
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define inff 200000000007
#define inf 0x3f3f3f
#define M 1007
#define MIN(a,b) a>b?b:a;
using namespace std;
struct E
{
    int v,w,next;
}edg[500000];
int dis[2000],gap[2000],head[2000],nodes;
int sourse,sink,nn;
int cow[M][2],n,s,t,countt;
long long g[M][M],maxx;
void init()
{
    nodes=0;maxx=0,countt=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i==j)g[i][j]=0;
            else g[i][j]=inff;
}
void floyd()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(g[i][k]+g[k][j]<g[i][j])
                    g[i][j]=g[i][k]+g[k][j];
}
long long findmin()
{
    long long maxxx=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(i!=j&&g[i][j]!=inff)
                maxxx=max(maxxx,g[i][j]);
    return maxxx;
}
void addedge(int u,int v,int w)
{
    edg[nodes].v=v;
    edg[nodes].w=w;
    edg[nodes].next=head[u];
    head[u]=nodes++;
    edg[nodes].v=u;
    edg[nodes].w=0;
    edg[nodes].next=head[v];
    head[v]=nodes++;
}
int dfs(int src,int aug)
{
    if(src==sink)return aug;
    int left=aug,mindis=nn;
    for(int j=head[src];j!=-1;j=edg[j].next)
    {
    	int v=edg[j].v;
    	if(edg[j].w)
        {
           if(dis[v]+1==dis[src])
           {
               int minn=MIN(left,edg[j].w);
               minn=dfs(v,minn);
               edg[j].w-=minn;
               edg[j^1].w+=minn;
               left-=minn;
               if(dis[sourse]>=nn)return aug-left;
               if(left==0)break;
           }
           if(dis[v]<mindis)
           mindis=dis[v];
        }
    }

        if(left==aug)
        {
            if(!(--gap[dis[src]]))dis[sourse]=nn;
            dis[src]=mindis+1;
            gap[dis[src]]++;
        }
        return aug-left;
}
int sap(int s,int e)
{
    int ans=0;
	nn=e+1;
    memset(dis,0,sizeof(dis));
    memset(gap,0,sizeof(gap));
    gap[0]=nn;
    sourse=s;
    sink=e;
    while(dis[sourse]<nn)
    ans+=dfs(sourse,inf);
    return ans;
}
bool search(long long mid)
{

    s=0,t=n+n+1,nodes=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    {
        addedge(s,i,cow[i][0]);
        addedge(i+n,t,cow[i][1]);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(g[i][j]<=mid)
                addedge(i,j+n,inf);
    if(sap(s,t)==countt)return true;
    return false;
}
long long solve()
{
    long long l=0,r=maxx,mid,ans=-1;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(search(mid)){ans=mid;r=mid-1;}
        else l=mid+1;
    }
    return ans;
}
int main()
{
    int m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        int a,b;
        long long c;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&cow[i][0],&cow[i][1]);
            countt+=cow[i][0];
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lld",&a,&b,&c);
            if(g[a][b]>c)g[a][b]=g[b][a]=c;
        }
        floyd();
        maxx=findmin();
        printf("%lld\n",solve());
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值