HDU - 2732 Leapin' Lizards (最大流 + 建图)

http://acm.hdu.edu.cn/showproblem.php?pid=2732

题意:

一个nxm的房间,有一些柱子,每个柱子有一个承受能力,有的柱子上面有蜥蜴,每只蜥蜴一次可以走K步,但是每到一个柱子上柱子的承受能力就会-1,为0是柱子会倒塌,问最后最多有多少只蜥蜴走出去,输出没走出去的蜥蜴的数量

思路:

思路很清晰,就是源点S 与蜥蜴建边权值为1,汇点T与能出去的柱子建边权值INF,然后柱子跟柱子之间建边INF,柱子与自身建边权值为自身的承受能力。
思路清晰,但是建图比较难,首先要用到 曼哈顿距离 来判断柱子与柱子,蜥蜴与柱子之间的距离,以此来建边。剩下的就是最大流的模版了。

#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <stdio.h>
#include <deque>

using namespace std;

#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 10005
#define eps 0.00000001
#define PI acos(-1.0)

struct Edge{
    int V, Weight, Next;
}edges[maxn << 2];


char Height[maxn][maxn];
char Maze[maxn][maxn];
int head[maxn << 1], Depth[maxn << 1], gap[maxn << 1], Cur[maxn << 1];
int tot, maxFlow, aug, isFind;
int S = 0, TT;
int N, D, MM, Cnt, Ans;

void init() {
    tot = 0;
    maxFlow = 0;
    memset(head, -1, sizeof(head));
    S = 0;
}

void AddEdge(int u, int v, int w) {
    edges[tot].V = v;
    edges[tot].Weight = w;
    edges[tot].Next = head[u];
    head[u] = tot ++;

    edges[tot].V = u;
    edges[tot].Weight = 0;
    edges[tot].Next = head[v];
    head[v] = tot ++;
}

bool Bfs(int Start, int End) {
    memset(Depth, -1, sizeof(Depth));
    std::queue<int> Que;
    Depth[Start] = 0;
    Que.push(Start);
    while (!Que.empty()) {
        int Vertex = Que.front();
        Que.pop();
        for (int i = head[Vertex]; i != -1; i = edges[i].Next) {
            if (Depth[edges[i].V] == -1 && edges[i].Weight > 0) {
                Depth[edges[i].V] = Depth[Vertex] + 1;
                Que.push(edges[i].V);
            }
        }
    }
    return Depth[End] != -1;
}

int Dfs(int Vertex, int End, int NowFlow) {
    if (Vertex == End || NowFlow == 0) {
        return NowFlow;
    }
    int UsableFlow = 0, FindFlow;
    for (int &i = Cur[Vertex]; i != -1; i = edges[i].Next) {
        if (edges[i].Weight > 0 && Depth[edges[i].V] == Depth[Vertex] + 1) {
            FindFlow = Dfs(edges[i].V, End, std::min(NowFlow - UsableFlow, edges[i].Weight));
            if (FindFlow > 0) {
                edges[i].Weight -= FindFlow;
                edges[i ^ 1].Weight += FindFlow;
                UsableFlow += FindFlow;
                if (UsableFlow == NowFlow) {
                    return NowFlow;
                }
            }
        }
    }
    if (!UsableFlow) {
        Depth[Vertex] = -2;
    }
    return UsableFlow;
}

int Dinic(int Start, int End) {
    int MaxFlow = 0;
    while (Bfs(Start, End)) {
        for (int i = 0; i <= N * MM * 2 + 1; ++i) {
            Cur[i] = head[i];
        }
        MaxFlow += Dfs(Start, End, INF);
    }
    return MaxFlow;
}




int main(int argc, const char * argv[]) {
    int T;
    scanf("%d", &T);
    for (int Case = 1; Case <= T; ++Case) {
        init();
        scanf("%d%d", &N, &D);
        for (int i = 1; i <= N; ++i) {
            scanf("%s", Height[i]);
            getchar();
        }
        MM = strlen(Height[1]);
        for (int i = 1; i <= N; ++i) {
            scanf("%s", Maze[i]);
            getchar();
        }
        Cnt = 0;
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= MM; ++j) {
                int Num = MM * (i - 1) + j;
                AddEdge(Num, N * MM + Num, (Height[i][j - 1] - '0'));
                if (Maze[i][j - 1] == 'L') {
                    AddEdge(0, Num, 1);
                    Cnt++;
                }
                bool flag = 0;
                for (int k = i - D; k <= i + D; ++k) {
                    for (int l = j - D; l <= j + D; ++l) {
                        if (k == i && l == j) {
                            continue;
                        }
                        if (k > 0 && k <= N && l > 0 && l <= MM) {
                            if (abs(k - i) + abs(l - j) <= D) {
                                AddEdge(N * MM + Num, MM * (k - 1) + l, INF);
                            }
                        }
                        else if (abs(k - i) + abs(l - j) <= D) {
                            if (!flag) {
                                AddEdge(N * MM + Num, N * MM * 2 + 1, INF);
                                flag = 1;
                            }
                        }
                    }
                }
            }
        }
        Ans = Cnt - Dinic(0, N * MM * 2 + 1);

        if (Ans == 0) {
            printf("Case #%d: no lizard was left behind.\n", Case);
        }
        else if (Ans == 1) {
            printf("Case #%d: %d lizard was left behind.\n", Case, Ans);
        }
        else {
            printf("Case #%d: %d lizards were left behind.\n", Case, Ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henu_jizhideqingwa/article/details/81981969