Skip to content

1019 Separate the Animals

Statement

Metadata

  • 作者: LIU, Rujia
  • 单位: 北京尔宜居科技有限责任公司
  • 代码长度限制: 16 KB
  • 时间限制: 1500 ms
  • 内存限制: 64 MB

There are some animals in a zoo which can be described as a grid with N rows and M columns. Your task is to place some obstacles so that no pairs of animals can reach each other.

Two animals can reach each other if and only if their cells are 4-connected. For example, in Figure 1, the central blue cell can be reached by the four red cells, and cannot be reached by the other four white cells.

sep1.JPG

Figure 1

What is more, you must put obstacles in exactly K cells, which are 4-connected and form exactly H holes. Here a hole is defined as a 4-connected part with finitely many open cells while the zoo is placed in an infinite open grid. For example, there are 2 holes (the green and the yellow areas) in Figure 2.

sep2.JPG

Figure 2

For the following grid with two animals:

sep3.jpg

Figure 3

If K = 8 and H = 1, one way to separate them is the following:

sep4.jpg

Figure 4

Figure 5 is illegal because it contains no hole.

sep5.jpg

Figure 5

Figure 6 is also illegal because the obstacles are not 4-connected.

sep6.jpg

Figure 6

Given some animals, you are supposed to count the number of different solutions.

Input Specification

Each input file contains one test case. For each case, the first line gives four integers: N, M, K, H (2 \le N, M \le 6; 1 \le K \le 12; 0 \le H \le 2). All the numbers are separated by spaces.

Then N lines follow, each contains M characters, which are either . or O, representing an open cell or an animal, respectively. There will be at least 2 animals.

Output Specification

For each case, print a single line containing a single integer: the number of solutions.

Sample Input

3 5 8 1
...O.
.O...
.....

Sample Output

8

Solution

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define dbg(x...)                             \
    do {                                      \
        cout << "\033[32;1m" << #x << " -> "; \
        err(x);                               \
    } while (0)
void err() {
    cout << "\033[39;0m" << endl;
}
template <class T, class... Ts>
void err(const T& arg, const Ts&... args) {
    cout << arg << ' ';
    err(args...);
}
int n, m, K, h;
const int N = 15;
char g[N][N];
int a[N][N], vis[N * N];

inline int id(int x, int y) {
    return (x - 1) * m + y;
}

unordered_map<ll, int> mp;

int fa[N * N], sze[N * N];
int find(int x) {
    return fa[x] == -1 ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
    x = find(x), y = find(y);
    if (x != y) {
        fa[x] = y;
        sze[y] += sze[x];
    }
}

int Move[][2] = {
        -1,
        0,
        0,
        -1,
        1,
        0,
        0,
        1,
};

inline bool valid(int x, int y) {
    if (x < 1 || x > n || y < 1 || y > m)
        return 0;
    return 1;
}

inline bool ok(ll sta) {
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            int ID = id(i, j);
            fa[ID] = -1;
            sze[ID] = (g[i][j] != '.');
            a[i][j] = ((sta >> ID) & 1);
            vis[ID] = a[i][j] ^ 1;
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j)
            if (a[i][j] == 0) {
                for (int k = 0; k < 2; ++k) {
                    int ni = i + Move[k][0];
                    int nj = j + Move[k][1];
                    if (valid(ni, nj) && a[ni][nj] == 0) {
                        merge(id(i, j), id(ni, nj));
                        if (sze[find(id(i, j))] > 1)
                            return false;
                    }
                }
            }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j)
            if (g[i][j] == 'o') {
                if (sze[find(id(i, j))] > 1) {
                    return false;
                }
            }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j)
            if (vis[id(i, j)] == 1) {
                for (int k = 0; k < 4; ++k) {
                    int ni = i + Move[k][0];
                    int nj = j + Move[k][1];
                    if (!valid(ni, nj)) {
                        vis[find(id(i, j))] = 0;
                        vis[id(i, j)] = 0;
                        break;
                    }
                }
            }
    }
    int cnt = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (fa[id(i, j)] == -1) {
                cnt += vis[id(i, j)];
            }
        }
    }
    return cnt == h;
}

void bfs() {
    int res = 0;
    queue<ll> que;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (g[i][j] == '.') {
                ll x = 1ll << id(i, j);
                //		dbg(i, j, x);
                que.push(x);
                mp[x] = 1;
            }
        }
    }
    while (!que.empty()) {
        ll sta = que.front();
        que.pop();
        if (__builtin_popcountll(sta) == K) {
            //		if (ok(sta)) dbg(sta);
            //		for (int i = 1; i <= n; ++i)
            //			printf("%s\n", g[i] + 1);
            res += ok(sta);
            continue;
        }
        if (__builtin_popcountll(sta) > K)
            continue;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                int ID = id(i, j);
                if (g[i][j] == '.' && ((sta >> ID) & 1) == 0) {
                    for (int k = 0; k < 4; ++k) {
                        int ni = i + Move[k][0];
                        int nj = j + Move[k][1];
                        if (valid(ni, nj) && ((sta >> id(ni, nj)) & 1) == 1) {
                            ll nx = sta ^ (1ll << ID);
                            if (mp.count(nx) == 0) {
                                que.push(nx);
                                mp[nx] = 1;
                            }
                            break;
                        }
                    }
                }
            }
        }
    }
    printf("%d\n", res);
}

int main() {
    scanf("%d%d%d%d", &n, &m, &K, &h);
    for (int i = 1; i <= n; ++i) scanf("%s", g[i] + 1);
    bfs();
    return 0;
}

Last update: May 4, 2022
Back to top