题目链接:https://cn.vjudge.net/contest/69431#problem/D

题意:

有一条河,河上有一些垃圾(看成点),人借助垃圾跳到对岸,已知垃圾坐标位置,人每次最大跳跃距离,河的

宽度以及人数,问是否所有人可以跳到对岸,若可以,求出最短时间。

解法:

第一次碰到动态流,还是队友推荐来做的。 题解来自:ORZ

我们知道时间的上限是n+m,因为对于第一个人他从一河岸跳到对岸最多踩m个垃圾,加上到达对岸的一步,

共需花m+1单位的时间,而第二个人他可以在第一人跳到第二个垃圾时重复第一人的跳法,也就是后面一人

比前面一人晚到对岸1个单位时间,那么有n-1人重复此过程,因此最大时间m+1+n-1=m+n,若超过此时

间,所有人未到对岸,显然是无解情况。

对于有解情况:我们先预处理所有垃圾两两之间的距离是否小于等于D,也就是能否在这些垃圾之间跳来跳

去,麻烦的是河岸并不是一个点,而是一条线,因此我们也要预处理能从左岸(出发地)跳到的垃圾(y坐标

<=D),和能从哪些垃圾跳到对岸(y坐标+D>=M).

然后根据时间拆点,记i点在t时刻的状态为(i,t),这里注意t=1,就是直接从左岸跳到对岸,这个可以判断

D>=M求得,然后我们从t=2开始枚举,这里要考虑清楚,我之前建模没想明白,t-1时刻,人是站在(i,t-

1)状态上的,那么t时刻人可以从(i,t-1)跳到对岸(如果满足条件的话),也就是要将所有(i,t-1)连

向汇点,千万不要将(i,t)连向汇点,当然也可以选择从(i,t-1)跳到(j,t)(i,j距离<=D),当然不要忘

了从左岸连向那些y坐标<=D的点(一步可达点),这样就差不多了。

最后别忘了,每个点需要拆成两个点,不这样做的话会有大量流量聚集在i点,然后通过下一时刻流出去,这

样就超过i在某一时刻最大人数限制了。此题拆点是挺麻烦的。

PS:这里最多会有10000割点左右,最坏情况有10^8条边,显然内存不允许,dinic算法也会TLE,所以可以推

断,数据显然不会出现这么多边和点的情况。所以随便开了2000000就AC。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 15000;
const int maxm = 2000000;
const int inf = 0x3f3f3f3f;
struct G
{
    int v, cap, next;
    G() {}
    G(int v, int cap, int next) : v(v), cap(cap), next(next) {}
} E[maxm];
int p[maxn], T;
int d[maxn], temp_p[maxn], qw[maxn]; //d顶点到源点的距离标号,temp_p当前狐优化,qw队列
void init()
{
    memset(p, -1, sizeof(p));
    T = 0;
}
void add(int u, int v, int cap)
{
    E[T] = G(v, cap, p[u]);
    p[u] = T++;
    E[T] = G(u, 0, p[v]);
    p[v] = T++;
}
bool bfs(int st, int en, int n)
{
    int i, u, v, head, tail;
    for(i = 0; i <= n; i++) d[i] = -1;
    head = tail = 0;
    d[st] = 0;
    qw[tail] = st;
    while(head <= tail)
    {
        u = qw[head++];
        for(i = p[u]; i + 1; i = E[i].next)
        {
            v = E[i].v;
            if(d[v] == -1 && E[i].cap > 0)
            {
                d[v] = d[u] + 1;
                qw[++tail] = v;
            }
        }
    }
    return (d[en] != -1);
}
int dfs(int u, int en, int f)
{
    if(u == en || f == 0) return f;
    int flow = 0, temp;
    for(; temp_p[u] + 1; temp_p[u] = E[temp_p[u]].next)
    {
        G& e = E[temp_p[u]];
        if(d[u] + 1 == d[e.v])
        {
            temp = dfs(e.v, en, min(f, e.cap));
            if(temp > 0)
            {
                e.cap -= temp;
                E[temp_p[u] ^ 1].cap += temp;
                flow += temp;
                f -= temp;
                if(f == 0)  break;
            }
        }
    }
    return flow;
}
int dinic(int st, int en, int n)
{
    int i, ans = 0;
    while(bfs(st, en, n))
    {
        for(i = 0; i <= n; i++) temp_p[i] = p[i];
        ans += dfs(st, en, inf);
    }
    return ans;
}
//最大流

bool g[55][55];
int n, m, val[55], xx[55], yy[55];
int getid(int id, int t, int p)
{
    return 2*n*(t-1)+p*n+id;
}
bool check(int t){
    init();
    int source = 0, sink = 2*n*t+1;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=t; j++){
            add(getid(i,j,0),getid(i,j,1),val[i]);
            if(j<t){
                add(getid(i,j,1),getid(i,j+1,0),inf);
            }
        }
    }
    for(int i=1; i<=n; i++){
        if(g[0][i]){
            for(int j=1; j<=t; j++) add(source, getid(i,j,0), inf);
        }
        if(g[i][n+1]){
            for(int j=1; j<=t; j++) add(getid(i,j,1), sink, inf);
        }
        for(int j=1; j<=n; j++){
            if(g[i][j]){
                for(int k=1; k<t; k++){
                    add(getid(i,k,1), getid(j,k+1,0), inf);
                }
            }
        }
    }
    int ans = dinic(source, sink, sink+2);
    return ans >= m;
}

int main()
{
    while(scanf("%d%d", &n,&m) != EOF)
    {
        memset(g, 0, sizeof(g));
        int d, w;
        scanf("%d%d", &d, &w);
        for(int i=1; i<=n; i++){
            scanf("%d%d%d",&xx[i],&yy[i],&val[i]);
        }
        if(w<=d){
            printf("1\n");
            continue;
        }
        for(int i=1; i<=n; i++){
            if(yy[i]<=d) g[0][i]=1;
            if(w-yy[i]<=d) g[i][n+1]=1;
            for(int j=1; j<=n; j++){
                if(i!=j){
                    if(sqrt((xx[i]-xx[j])*(xx[i]-xx[j])+(yy[i]-yy[j])*(yy[i]-yy[j])) <= d){
                        g[i][j]=g[j][i]=1;
                    }
                }
            }
        }
        int ans = -1, l=1, r=102;
        while(l <= r){
            int mid = (l+r)/2;
            if(check(mid)) ans = mid, r = mid-1;
            else l = mid+1;
        }
        if(ans == -1) printf("IMPOSSIBLE\n");
        else printf("%d\n", ans+1);
    }
    return 0;
}