sug438 The Glorious Karlutka River =)(枚举+最大流)

438. The Glorious Karlutka River =)
Time limit per test: 1 second(s)
Memory limit: 262144 kilobytes
input: standard
output: standard



A group of  M tourists are walking along the Karlutka river. They want to cross the river, but they couldn't find a bridge. Fortunately, there are some piles of rubbish floating in the water, and the  tourists have decided to try to cross the river by jumping from one pile to another.

tourist can move up to  D meters in any direction at one jump. One jump takes exactly one second.  tourists know that the river is W meters wide, and they have estimated the coordinates of rubbish piles ( X iY i) and the capacity of each pile ( C i, the maximum number of  tourists that this pile can hold at the same time). Rubbish piles are not very large and can be represented as points. The river flows along the  X axis.  tourists start on the river bank at 0 by  Y axis. The  Y coordinate of the opposite bank is  W.

tourists would like to know if they can get to the opposite bank of the river, and how long it will take.

Input
First line of input consists of four integers: number of rubbish piles  N (0 ≤  N ≤ 50), number of  touristM (0 <  M ≤ 50), maximum length of  tourist's jump  D (0 ≤  D ≤ 1000), and width of the river  W (0 <  W ≤ 1000) Following  N lines describe the rubbish piles, each line consists of three integers: (0 <  X i < 1000, 0 <  Y i <  W, 0 ≤  C i ≤ 1000) — pile coordinates and capacity.

Output
Output a single number indicating the minimal time (in seconds) in which all  tourists will be able to cross the river, or the line " IMPOSSIBLE" if it is impossible to cross the river.

Example(s)
sample input
sample output
3 10 3 7
0 2 2
4 2 2
2 4 3
6

sample input
sample output
3 10 3 8
0 2 2
4 2 2
2 4 3
IMPOSSIBLE


分析:这题与hdu1733 Escape类似,关键在建图时不只第一个时间可以连接源点,对于每一层都必须连上源点,而且第一层不能一开始连上汇点,而应等下一层出现再连上汇点,详细构图见http://hi.baidu.com/fp_h/blog/item/f381e1df6c747c2e5982dd94.html

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=438

这个oj爆内存同样给了个tle生气。。。注意容量为0的点要删掉

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int mm=2222222;
const int mn=55555;
const int oo=1000000000;
int node,src,dest,edge,ret,ans;
int reach[mm],flow[mm],next[mm];
int head[mn],work[mn],dis[mn],q[mn];
int x[mn],y[mn],c[mn];
bool vis[55],get[55][55];
int i,j,k,m,n,w,d;
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline void addedge(int u,int v,int c)
{
    reach[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++;
    reach[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++;
}
inline void makegraph(int cc,int add)
{
    int i,j,w=node-2;
    while(add--)head[node++]=-1;
    for(i=2;i<=n+1;++i)
    {
        addedge(w+i,w+i+n,c[i]);
        if(get[src][i])addedge(src,w+i,oo);
        if(cc)
        {
            if(get[i][dest])addedge(w+i-n,dest,oo);
            addedge(w+i-n,w+i,oo);
            for(j=2;j<=n+1;++j)
                if(i!=j&&get[i][j])
                    addedge(w+i-n,w+j,oo);
        }
    }
}
bool Dinic_bfs()
{
    int i,u,v,l,r=0;
    for(i=0; i<node; ++i)dis[i]=-1;
    dis[q[r++]=src]=0;
    for(l=0; l<r; ++l)
        for(i=head[u=q[l]]; i>=0; i=next[i])
            if(flow[i]&&dis[v=reach[i]]<0)
            {
                dis[q[r++]=v]=dis[u]+1;
                if(v==dest)return 1;
            }
    return 0;
}
int Dinic_dfs(int u,int exp)
{
    if(u==dest)return exp;
    for(int &i=work[u],v,tmp; i>=0; i=next[i])
        if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
        {
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            return tmp;
        }
    return 0;
}
int Dinic_flow()
{
    int i,delta;
    while(Dinic_bfs())
    {
        for(i=0; i<node; ++i)work[i]=head[i];
        while(delta=Dinic_dfs(src,oo))ret+=delta;
    }
    return ret;
}
void dfs(int i)
{
    vis[i]=1;
    for(int j=0;j<=n+1;++j)
        if(!vis[j]&&get[i][j])dfs(j);
}
bool tryit(int x1,int y1,int x2,int y2)
{
    return sqrt(double(x1-x2)*(x1-x2)+double(y1-y2)*(y1-y2))<=d;
}
int main()
{
    while(scanf("%d%d%d%d",&n,&m,&d,&w)!=-1)
    {
        memset(get,0,sizeof(get));
        for(i=1,j=2; i<=n; ++i)
        {
            scanf("%d%d%d",&x[j],&y[j],&c[j]);
            if(c[j])++j;
        }
        n=j-1-(c[j]==0);
        for(i=2; i<=n+1; ++i)
        {
            get[0][i]=get[i][0]=y[i]<=d;
            get[1][i]=get[i][1]=w-y[i]<=d;
            for(j=i+1; j<=n+1; ++j)get[j][i]=get[i][j]=tryit(x[i],y[i],x[j],y[j]);
        }
        get[0][1]=get[1][0]=w<=d;
        if(w<=d)
        {
            printf("1\n");
            continue;
        }
        for(i=0;i<=n+1;++i)vis[i]=0;
        dfs(0);
        if(!vis[1])
        {
            printf("IMPOSSIBLE\n");
            continue;
        }
        node=2,edge=ret=src=0,ans=dest=1;
        head[0]=head[1]=-1;
        makegraph(0,n*2);
        while(Dinic_flow()<m)++ans,makegraph(1,n*2);
        printf("%d\n",ans);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值