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;
}