POJ 2391 Ombrophobic Bovines //FLOTED+二分+SAP

来源:互联网 发布:双喜软件价格 编辑:程序博客网 时间:2024/05/21 17:23

Ombrophobic Bovines
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 5167 Accepted: 1168

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 47 20 42 61 2 403 2 702 3 901 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

 

 

 

写的挺纠结,上次就这道题,总是过不去,就卡着了。

今天一大早起来读题,中午慢慢悠悠写,又调试,搞了3个小时,WA了好几次,终于过了这道题

 

首先是建图,我记得我上次做这道题,就是没有拆点,但是可能因为是无向图,也可能是因为不拆点可能造成回流,这是不行的

今天早上一直在想建图,想的差不多对于建图。

接着就是整个过程,现实FLOYED,再是将所有的点保存在一个队列中,对队列进行排序,接着二分队列就可以了。

我的二分不知道为什么,总是做二分就不顺,今天也不是很顺。

 

并且那个__INT64,我没弄清楚,下次有__INT64的题就别用INT,这里用INT哪里用长整型,容易错啊!

 

至于建图,就是将每个点拆开为i,i+n,接着源点0向每个i节点连接边,边为刚开始的牛的数目,结合每个i+n节点连接汇点2n+1,边长为每个田能容纳下的牛数,接着每个i和i+n连无穷大的边,要是i和j田也能连接,就连i和i+n,j连i+n,就哦了!

哈哈

 

别人的评论

http://www.cppblog.com/abilitytao/archive/2010/11/11/133348.html

这提相当经典啊,这题相当猥琐啊。。。。
无向图中给出N个点,M条边,每个点有当前囤积流量和最大容量,任意两个点之间有距离,首先保证所有的流量都可以被节点吸收(即不超过最大容量),然后将流量跑的最大距离限制到最小。
做法:SAP+二分+Floyd
1.首先预处理出任意两点之间的最短路,二分最大距离mid;
2.将每个节点拆成i*2 i*2+1,i*2+1代表流出的点out[i],i*2代表流进的点in[i],前者向后者连一条INF的边。
3.建立超级源s,向每个点in[i],连一条当前囤积流量的边,每个点out[i]向超级汇t连一条最大容量的边。
4.在floyd之后的数组中枚举每两个点之间的最短距离,如果<=mid就建立一条in[i]->out[j]的边
跑最大流,如果满流,下降上界,否则提高下界。

这题做了收获很大,学会了控制初始流量的方法和最后流量全部控制在容量内的方法。
另外就是拆点,分成两个点之后,限制了只要进来的流量就一定囤积在该点,由于这个点本身有初始流量,两个点之间连的那条边可以保证自己的流量也可以不流走。非常精彩的构图^_^
PS:顺便说一下的是:虽然这个图是无向图,但是根据题意,走任意方向互不干扰,所以可以拆成两条有向边。一旦有流量经过这条边,那么流量不会流走,也就说明这个流量必须也只能走这么长的距离,这个锁定技巧很不错,于是就能二分了。。。

 

 

对于这个疑问

1.为什么很多人说要拆点,拆点后两点间边无穷,和不拆有什么区别吗?2.若按照普通见图,FLOYD后,再二分最长长度求最大流,则若有流量流过2条边怎么办?  本来在规定长度内不可达的点就可达了。

可以试试这个数据

3 21 00 00 11 2 12 3 1拆点后, 由于没有边从i'到i从而起到了对i点限制作用,即不允许其他流通过该点到达该点能到达的点, ,比如上面的1到3就不能在t=1时到达, 

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
__int64 n,m,e,sum,nn;
__int64 f[410],p[410];
__int64 map[410][410];
__int64 rmin,rmax,mid;
__int64 flow[410][410],dist[410],gap[410];
struct EDGE
{
    int x,y;
    __int64 c;
    EDGE() {}
    EDGE(int a,int b,__int64 cc):x(a),y(b),c(cc) {}
} edge[410*410];
__int64 min(__int64 a,__int64 b)
{
    if(a<b)  return a;
    return b;
}
bool cmp(EDGE a,EDGE b)
{
    return a.c<b.c;
}
void floyed()
{
    for(int k=1; k<=n; k++)
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                if(i!=j&&map[i][k]!=-1&&map[k][j]!=-1)
                {
                    if(map[i][j]!=-1)  map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
                    else map[i][j]=map[i][k]+map[k][j];
                }
}
__int64 find_path(int p,__int64 limit=edge[e-1].c+1)
{
    if(p==nn-1) return limit;
    for (int i=0;i<nn;++i)
    {
        if(dist[p]==dist[i]+1 && flow[p][i]>0)
        {
            __int64 t=find_path(i,min(limit,flow[p][i]));
            if(t<0) return t;
            if(t>0)
            {
                flow[p][i]-=t;
                flow[i][p]+=t;
                return t;
            }
        }
    }
    int label=nn;
    for(int i=0;i<nn;++i)
        if(flow[p][i]>0) label=min(label,dist[i]+1);
    if(--gap[dist[p]]==0 || dist[0]>=nn) return -1;
    ++gap[dist[p] = label];
    return 0;
}
__int64 iSAP()
{
    memset(flow,0,sizeof(flow));
    memset(gap,0,sizeof(gap));
    memset(dist,0,sizeof(dist));//
    for(int i=1;i<=n;i++)  flow[i][i+n]=edge[e-1].c+1;;
    for(int i=0;i<=mid;i++)
    {
        int x=edge[i].x;
        int y=edge[i].y;
        __int64 c=edge[i].c;
        flow[x][y+n]=edge[e-1].c+1;
        flow[y][x+n]=edge[e-1].c+1;
    }
    for(int i=1;i<=n;i++)
    {
       if(f[i]!=0)
          flow[0][i]=f[i];
       if(p[i]!=0)
           flow[i+n][2*n+1]=p[i];
    }
    nn=n*2+2;
    gap[0]=nn;
    __int64 maxflow=0,t=0;
    while((t=find_path(0))>=0) maxflow+=t;
    return maxflow;
}
void solve()
{
    __int64 ans=edge[rmin].c;
    bool flag=false;
    rmin=0,rmax=e-1;
    while(rmin<=rmax)
    {
        mid=(rmin+rmax)>>1;
        if(iSAP()==sum)
        {
           ans=edge[mid].c;
           flag=true;
           rmax=mid-1;
        }
        else rmin=mid+1;
    }
    if(flag)
    printf("%I64d/n",ans);
    else
    printf("-1/n");
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        e=0;
        sum=0;
        memset(map,-1,sizeof(map));
        for(int i=1; i<=n; i++)  map[i][i]=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&f[i],&p[i]);
            sum+=f[i];
        }
        for(int i=1; i<=m; i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(map[a][b]!=-1)   map[a][b]=map[b][a]=min(map[a][b],c);
            else map[a][b]=map[b][a]=c;
        }
        floyed();
        for(int i=1; i<=n; i++)
            for(int j=i+1; j<=n; j++)
                if(map[i][j]!=-1) edge[e++]=EDGE(i,j,map[i][j]);
        sort(edge,edge+e,cmp);
        solve();
    }
    return 0;
}