【SGU438】The Glorious Karlutka River =) 分层图最大流

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.

A 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 (Xi, Yi) and the capacity of each pile (Ci, 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 tourists M (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 < Xi < 1000, 0 < Yi < W, 0 ≤ Ci ≤ 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
3 10 3 7
0 2 2
4 2 2
2 4 3

sample output
6

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

IMPOSSIBLE

有一条河,宽为w,有n个垃圾袋在河上,m个人想踩垃圾袋过河。第i个垃圾袋同一时刻只能承载ci人,每人一秒钟只能跳一下,最远跳跃距离是d。现在给你n个垃圾袋的坐标,m个人想从直线y=0以下跳到y=w以上,问全部通过的最少时间。

每个垃圾袋拆点,点容量放在边上,然后按时间拆点。注意源点要向各个时间线的所有能到达的石头连边,汇点也是。

有一个疑问,为什么dfs判断可行之后还有可能无法全部通过?为什么在ans很大之后无解就要IMPOSSIBLE??

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;

const int INF = 1000000010;
const int SZ = 2000010;

int n;

int head[SZ],nxt[SZ],tot = 1;

struct edge{
    int t,d;
}l[SZ];

void build(int f,int t,int d)
{
    l[++ tot].t = t;
    l[tot].d = d;
    nxt[tot] = head[f];
    head[f] = tot;
}

void insert(int f,int t,int d)
{
    build(f,t,d); build(t,f,0);
}

int deep[SZ];
queue<int> q;

bool bfs(int s,int e)
{
    memset(deep,0,sizeof(deep));
    deep[s] = 1;
    while(q.size()) q.pop();
    q.push(s);
    while(q.size())
    {
        int u = q.front(); q.pop();
        for(int i = head[u];i;i = nxt[i])
        {
            int v = l[i].t;
            if(!deep[v] && l[i].d)
            {
                deep[v] = deep[u] + 1;
                q.push(v);
                if(v == e) return true;
            }
        }
    }
    return false;
}

int dfs(int u,int flow,int e)
{
    if(u == e || flow == 0) return flow;
    int rest = flow;
    for(int i = head[u];i;i = nxt[i])
    {
        int v = l[i].t;
        if(deep[v] == deep[u] + 1 && l[i].d)
        {
            int f = dfs(v,min(l[i].d,rest),e);
            if(f > 0)
            {
                l[i].d -= f;
                l[i ^ 1].d += f;
                rest -= f;
                if(rest == 0) break;
            }
            else deep[v] = 0;
        }
    }
    return flow - rest;
}

int dinic(int s,int e)
{
    int ans = 0;
    while(bfs(s,e)) ans += dfs(s,INF,e);
    return ans;
}

double getdist(int x1,int y1,int x2,int y2)
{
    double a = x1 - x2;
    double b = y1 - y2;
    return sqrt(a * a + b * b);
}

int getnode(int p,int ans)
{
    return p + ans * 2 * n;
}

int xx[SZ],yy[SZ],cc[SZ];

bool dist[233][233];
bool vis[SZ];
int m,d,w;

bool dfs(int u)
{
    if(cc[u] == 0) return false;
    if(w - yy[u] <= d) return true;
    vis[u] = 1;
    for(int i = 1;i <= n;i ++)
        if(!vis[i] && dist[i][u] <= d)
            if(dfs(i)) return true;
    return false;
}

bool check()
{
    for(int i = 1;i <= n;i ++)
        if(yy[i] <= d) 
            if(dfs(i)) return true;
    return false;
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&d,&w);
    for(int i = 1;i <= n;i ++)
        scanf("%d%d%d",&xx[i],&yy[i],&cc[i]);

    for(int i = 1;i <= n;i ++)
        for(int j = 1;j <= n;j ++)
            dist[i][j] = getdist(xx[i],yy[i],xx[j],yy[j]) <= d ? 1 : 0;


    if(d >= w) { puts("1"); return 0; }
    if(!check()) { puts("IMPOSSIBLE"); return 0; }


    int s = 0,e = 200000;

    for(int i = 1;i <= n;i ++)
        insert(i,i + n,cc[i]);
/*  for(int i = 1;i <= n;i ++)
    {
        if(yy[i] <= d)
            insert(s,i,INF);
        if(w - yy[i] <= d)
            insert(i + n,e,INF);
    }*/

    int ans = 0,sum = 0;
    while(ans < 233)
    {
        sum += dinic(s,e);
        if(sum >= m) break;
        for(int i = 1;i <= n;i ++)
            for(int j = 1;j <= n;j ++)
                if(i != j && dist[i][j])
                    insert(getnode(i + n,ans),getnode(j,ans + 1),INF);
        for(int i = 1;i <= n;i ++)
            insert(getnode(i,ans + 1),getnode(i + n,ans + 1),cc[i]);
        for(int i = 1;i <= n;i ++)
        {
            if(yy[i] <= d)
                insert(s,getnode(i,ans + 1),INF);
            if(w - yy[i] <= d)
                insert(getnode(i + n,ans + 1),e,INF);
        }   

        ans ++; 
    }
    if(ans < 233) printf("%d",ans + 1);
    else puts("IMPOSSIBLE");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值