SGU 438 - The Glorious Karlutka River =)(网络流‘最大流)

来源:互联网 发布:邮件服务器软件 编辑:程序博客网 时间:2024/06/08 08:20

题目:

http://acm.sgu.ru/problem.php?contest=0&problem=438

题意:

河中有N块石头,河宽是W,M个游客,游客最多可以跳D米,每跳一次耗时1s。

给出N块石头的坐标和承重量,游客在南岸出发(即x轴)。问是否能够全部通过河,若能通过则求出最少用时。

思路:

动态流问题。在限制流量的情况下加入时间的限制。

通过枚举时间来建图,将每一时刻的流量加起来,得到的总流量超过人数则输出此刻的时间。

建立一个分层网络,随着时间的增加加入新的边,得到新的网络流量。对石头进行拆点。

AC.

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <queue>using namespace std;int M, D, W;struct node {    int x, y, c;}dist[55];bool d[55][55];const int MAXN = 1e5+10;const int MAXM = 8e5+10;const int INF = 0x3f3f3f3f3f;struct Edge{int to,next,cap,flow;}edge[MAXM];int tol;int head[MAXN];int gap[MAXN],dep[MAXN],cur[MAXN];void init(){    tol = 0;    memset(head,-1,sizeof(head));}void addedge(int u,int v,int w,int rw = 0){    edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;    edge[tol].next = head[u]; head[u] = tol++;    edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;    edge[tol].next = head[v]; head[v] = tol++;}int Q[MAXN];void BFS(int start,int end){    memset(dep,-1,sizeof(dep));    memset(gap,0,sizeof(gap));    gap[0] = 1;    int front = 0, rear = 0;    dep[end] = 0;    Q[rear++] = end;    while(front != rear)    {        int u = Q[front++];        for(int i = head[u]; i != -1; i = edge[i].next)        {            int v = edge[i].to;            if(dep[v] != -1)continue;            Q[rear++] = v;            dep[v] = dep[u] + 1;            gap[dep[v]]++;        }    }}int S[MAXN];int sap(int start,int end, int N){    BFS(start,end);    memcpy(cur,head,sizeof(head));    int top = 0;    int u = start;    int ans = 0;    while(dep[start] < N)    {        if(u == end)        {            int Min = INF;            int inser;           for(int i = 0;i < top;i++)                if(Min > edge[S[i]].cap - edge[S[i]].flow)                {                    Min = edge[S[i]].cap - edge[S[i]].flow;                    inser = i;                }            for(int i = 0;i < top;i++)            {                edge[S[i]].flow += Min;                edge[S[i]^1].flow -= Min;            }            ans += Min;            top = inser;            u = edge[S[top]^1].to;            continue;        }        bool flag = false;        int v;        for(int i = cur[u]; i != -1; i = edge[i].next)        {            v = edge[i].to;            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])            {                flag = true;                cur[u] = i;                break;            }        }        if(flag)        {            S[top++] = cur[u];            u = v;            continue;        }        int Min = N;        for(int i = head[u]; i != -1; i = edge[i].next)            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)            {                Min = dep[edge[i].to];                cur[u] = i;            }        gap[dep[u]]--;        if(!gap[dep[u]])return ans;        dep[u] = Min + 1;        gap[dep[u]]++;        if(u != start)u = edge[S[--top]^1].to;    }    return ans;}bool judge(int a, int b){    int dis = (dist[a].x - dist[b].x)*(dist[a].x - dist[b].x)                    + (dist[a].y - dist[b].y)*(dist[a].y - dist[b].y);    if(D*D >= dis) return true;    return false;}int main(){    //freopen("in", "r", stdin);    int N;    while(~scanf("%d %d %d %d", &N, &M, &D, &W)) {        for(int i = 1; i <= N; ++i) {            scanf("%d%d%d", &dist[i].x, &dist[i].y, &dist[i].c);        }        if(D >= W) {            printf("1\n");            continue;        }            memset(d, 0, sizeof(d));            for(int i = 1; i <= N; ++i) {                for(int j = 1; j <= N; ++j) {                    if(i != j && judge(i, j)) {                        d[i][j] = 1;                    }                }            }            int sum = 0;            int s = 0, t = (M+N+1)*50+5000+1, ok = 0;            init();            for(int ti = 1; ti <= N+M; ++ti) {                for(int i = 1; i <= N; ++i) {                    addedge(ti*50+i, ti*50+5000+i, dist[i].c);                    if(dist[i].y <= D) {                        addedge(s, ti*50+i, INF);                    }                    if(dist[i].y + D >= W) {                        addedge(ti*50+5000+i, t, INF);                    }                    for(int j = 1; j <= N; ++j) {                        if(d[i][j]) {                            addedge(ti*50+5000+i, (ti+1)*50+j, INF);                        }                    }                }                sum += sap(s, t, t+1);                //printf("%d\n", sum);                if(sum >= M) {                    printf("%d\n", ti+1);                    ok = 1;                    break;                }            }            if(!ok) printf("IMPOSSIBLE\n");    }    return 0;}




0 0