Description
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
Input
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
Output
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
Sample Input
5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
Sample Output
1
HINT
100%的数据满足:1<=r, c<=20, 1<=d<=3
一道比較簡單的最大流算法。拆點:將每個點拆成上下兩個點,若該位置有石柱,則將該位置從上點到下點連一條邊,權值為該石柱的高度;
若能從A石柱跳到B石柱,則從A位置的下點到B位置的上點連一條權值為正無窮的邊;
增加超級源S,從S到每個有蜥蜴的位置的上點連一條權值為1的邊;
增加超級汇T,從能夠跳出邊界的每一個石柱的下點到T連一條權值為正無窮的邊。
然後用SAP算法求解即可。
Accode:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>
#include <cmath>
const char fi[] = "lizard.in";
const char fo[] = "lizard.out";
const int maxN = 1010;
const int maxR = 30;
const int MAX = 0x3fffff00;
const int MIN = -MAX;
int h[maxR][maxR];
int f[maxN][maxN];
int d[maxN], cnt[maxN];
int x[maxN], y[maxN];
int up[maxR][maxR];
int down[maxR][maxR];
std::bitset <maxN> t;
int N, M, n = 1, D, ans;
void init_file()
{
freopen(fi, "r", stdin);
freopen(fo, "w", stdout);
}
inline int sqr(int x) {return x * x; }
void readdata()
{
scanf("%d%d%d", &N, &M, &D);
for (int i = 1; i < N + 1; ++i)
{
getchar();
for (int j = 1; j < M + 1; ++j)
{
h[i][j] = getchar() - '0';
if (h[i][j] > 0)
{
t.set(++n);
up[i][j] = n;
x[n] = i;
y[n] = j;
f[n][n + 1] = h[i][j];
//注意上一行的n + 1不能用++n,
//因為同一表達式的各部分計算順序不確定。
t.reset(++n);
down[i][j] = n;
x[n] = i;
y[n] = j;
}
}
}
++n;
for (int i = 1; i < N + 1; ++i)
for (int j = 1; j < M + 1; ++j)
if (h[i][j] > 0 && (i <= D ||
j <= D || i > N - D || j > M - D))
f[down[i][j]][n] = MAX;
for (int i = 2; i < n; ++i)
for (int j = 2; j < n; ++j)
if (!t.test(i) && t.test(j)
&& (x[i] != x[j] || y[i] != y[j])
&& sqrt(sqr(x[i] - x[j])
+ sqr(y[i] - y[j])) <= D)
f[i][j] = MAX;
for (int i = 1; i < N + 1; ++i)
{
getchar();
for (int j = 1; j < M + 1; ++j)
if (getchar() == 'L' && h[i][j] > 0)
{f[1][up[i][j]] = 1; ++ans; }
}
}
int Sap(int u, int Lim)
{
if (u == n) return Lim;
int tmp = 0;
for (int v = 1; v < n + 1; ++v)
if (f[u][v] > 0 && d[u] == d[v] + 1)
{
int k = Sap(v, std::min(Lim
- tmp, f[u][v]));
if (k <= 0) continue;
f[u][v] -= k;
f[v][u] += k;
if ((tmp += k) == Lim) return tmp;
}
if (d[1] >= n) return tmp;
if ((--cnt[d[u]]) <= 0) d[1] = n;
++cnt[++d[u]];
return tmp;
}
void work()
{
cnt[0] = n;
while (d[1] < n) ans -= Sap(1, MAX);
printf("%d\n", ans);
}
int main()
{
init_file();
readdata();
work();
exit(0);
}