SGU 438 动态网络流,SGU挂了,我也不知道A没A

来源:互联网 发布:无锡服务器数据恢复 编辑:程序博客网 时间:2024/05/16 18:13

题目链接: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;}
0 0
原创粉丝点击