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

Data Range

100% 的数据满足:\(1 \leq r, c \leq 20, 1 \leq d \leq 4\)

Explanation

此题用网络流过掉, 但是还是拆点, 而且是经典的把一个几何点拆成两个拓扑点. 比如一个 点负责流入, 另一个流出; 流入和流出之间一定有一个限制流量即允许从该处跳出的青蛙数量. 进一步地, 可以从一个流出连到另一个流入, 即青蛙的移动法则.

大概瞎搞一发 Dinic 可以水过......

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cstring>

#define rep(_var,_begin,_end) for (int _var=_begin;_var<=_end;_var++)
#define sqr(__x) ((__x)*(__x))
using namespace std;
typedef long long lli;
const int maxN = 100, maxn = 10100, maxm = 500100;
const int infinit = 0x0f7f7f7f;

class Dinic
{
public:
    struct edge
    {
        int u, v, flow;
        edge *next, *rev;
    };
    int n, s, t, ecnt;
    edge *edges[maxn], epool[maxm];
    int level[maxn];
    void add_edge(int u, int v, int flow)
    {
//        printf("%d %d %d\n", u, v, flow);
        edge *p = &epool[++ecnt],
             *q = &epool[++ecnt];
        p->u = u; p->v = v; p->flow = flow;
        p->next = edges[u]; edges[u] = p; p->rev = q;
        q->u = v; q->v = u; q->flow = 0;
        q->next = edges[v]; edges[v] = q; q->rev = p;
        return ;
    }
    bool make_level(void)
    {
        memset(level, 0, sizeof(level));
        queue<int> que;
        que.push(s);
        level[s] = 1;
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            for (edge *ep = edges[p]; ep; ep = ep->next)
                if (ep->flow && !level[ep->v]) {
                    level[ep->v] = level[p] + 1;
                    que.push(ep->v);
                }
        }
        if (level[t] > 0)
            return true;
        return false;
    }
    int dfs(int p, int mn)
    {
        if (p == t)
            return mn;
        int sum = 0, tmp;
        for (edge *ep = edges[p]; ep && sum < mn; ep = ep->next)
            if (ep->flow && level[ep->v] == level[p] + 1) {
                tmp = dfs(ep->v, min(mn - sum, ep->flow));
                if (tmp > 0) {
                    sum += tmp;
                    ep->flow -= tmp;
                    ep->rev->flow += tmp;
                }
            }
        return sum;
    }
    int eval(void)
    {
        int sum = 0, tmp;
        while (make_level()) {
            tmp = dfs(s, infinit);
            if (tmp <= 0)
                break;
            sum += tmp;
        }
        return sum;
    }
} graph;

int read_number(void) { char ch = '\0';
    while (ch < '0' || ch > '9') ch = getchar();
    return ch - '0'; }
bool read_position(void) { char ch = '\0';
    while (ch != '.' && ch != 'L') ch = getchar();
    return ch == 'L'; }

int r, c, d;
int arr[maxN][maxN];
#define get_pos(__y,__x) (((__y)-1)*c+(__x))

bool judge_node_pair(int x1, int y1, int x2, int y2)
{
//    if (x1 < 1 || x1 > c || x2 < 1 || x2 > c) return false;
//    if (y1 < 1 || y1 > r || y2 < 1 || y2 > r) return false;
    if (x1 == x2 && y1 == y2) return false;
    if (!arr[x1][y1] || !arr[x2][y2]) return false;
    return sqr(x1 - x2) + sqr(y1 - y2) <= sqr(d);
}

int main(int argc, char **argv)
{
    scanf("%d%d%d", &r, &c, &d);
    graph.n = r * c * 2 + 2;
    graph.s = 0;
    graph.t = 801;
    int tot_cnt = 0; // All lizards
    for (int i = 1; i <= r; i++)
        for (int j = 1; j <= c; j++)
            arr[i][j] = read_number();
    // Linking from source to entries
    rep(i, 1, r) rep(j, 1, c)
        if (read_position()) {
            graph.add_edge(graph.s, get_pos(i,j), 1);
            tot_cnt++;
        }
    // Building exit portals to sink
    rep(i, 1, d) rep(j, d+1, r-d) {
        graph.add_edge(get_pos(j,i) + 400, graph.t, infinit);
        graph.add_edge(get_pos(j,c-i+1) + 400, graph.t, infinit);
    }
    rep(i, 1, d) rep(j, 1, c) {
        graph.add_edge(get_pos(i,j) + 400, graph.t, infinit);
        graph.add_edge(get_pos(r-i+1,j) + 400, graph.t, infinit);
    }
    // Building edges between nodes
    rep(x1, 1, r) rep(y1, 1, c) rep(x2, x1-d, x1+d) rep(y2, y1-d, y1+d)
        if (judge_node_pair(x1, y1, x2, y2))
            graph.add_edge(get_pos(x1,y1) + 400, get_pos(x2,y2), infinit);
    // Building flow limit in a single node
    rep(i, 1, r) rep(j, 1, c)
        if (arr[i][j])
            graph.add_edge(get_pos(i,j), get_pos(i,j) + 400, arr[i][j]);
    // Executing maximum flow
    int res = graph.eval();
    printf("%d\n", tot_cnt - res);
    return 0;
}