[ABC219E] Moat 題解
思路解析
一眼看到輸入資料只有 \(4\) 行 \(4\) 列,直接想到狀壓列舉。可以直接列舉所有護城河所包含起來的格子,判斷是否連通以及判斷是否包含住了所有村莊。判斷連通我選擇用洪水填充,隨便選一個包含著的格子,若可以透過當前格移動到所有被包含格就說明連通。以及還要判斷被包圍格子是否形成了一個環,例如:
其中藍線表示護城河,綠色陰影表示護城河包圍的格子。可見圖中有兩條護城河,不符合題意。為排除掉這種情況,我們判斷每一個沒有被選擇的格子,判斷它是否被護城河完全包圍,也就是判斷能否走到地圖外即可。
時間複雜度:首先一次暴力列舉,然後對於每種情況需要判斷是否為可行方案,洪水填充最多遍歷 \(16\) 個格子,複雜度為 \(2^{16} \times 16\)。
code
#include<bits/stdc++.h>
using namespace std;
#define PII pair<int, int>
#define fir first
#define sec second
int v[8][8], flag[8][8], f[8][8], ans = 0;
bool vis[8][8];
int dx[4] = {0, 0, -1, 1};
int dy[4] = {-1, 1, 0, 0};
void flood(int x, int y) {
queue< PII > q;
q.push({x, y});
while(!q.empty()) {
int xx = q.front().fir, yy = q.front().sec;
q.pop();
for(int i = 0; i < 4; i++) {
int nx = xx + dx[i], ny = yy + dy[i];
if(flag[nx][ny] && !f[nx][ny]) {
f[nx][ny] = true;
q.push({nx, ny});
}
}
}
}
bool flood_loop(int x, int y) {
queue< PII > q;
q.push({x, y});
memset(vis, false, sizeof(vis));
vis[x][y] = true;
while(!q.empty()) {
int xx = q.front().fir, yy = q.front().sec;
q.pop();
for(int i = 0; i < 4; i++) {
int nx = xx + dx[i], ny = yy + dy[i];
if(!flag[nx][ny] && !vis[nx][ny]) {
if(nx >= 1 && nx <= 4 && ny >= 1 && ny <= 4) {
vis[nx][ny] = true;
q.push({nx, ny});
}
else return true;
}
}
}
return false;
}
int check() {
int x = 0, y = 0, cnt = 0;
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 4; j++) {
if(flag[i][j]) cnt++, x = i, y = j;
}
}
memset(f, 0, sizeof(f));
f[x][y] = 1;
flood(x, y); //洪水填充判斷連通
int sum = 0;
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 4; j++) {
if(f[i][j]) sum++;
}
}
if(sum != cnt) return 0; //不連通
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 4; j++) {
if(v[i][j] && !f[i][j]) return 0; //若有村莊沒被包含
}
}
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 4; j++) {
if(!flag[i][j] && !flood_loop(i, j)) return 0; //被護城河完全包圍
}
}
return 1;
}
void dfs(int x, int y) { //暴力列舉
if(y > 4) y = 1, x++;
if(x > 4) {
ans += check();
return;
}
flag[x][y] = 1;
dfs(x, y + 1);
flag[x][y] = 0;
dfs(x, y + 1);
}
int main() {
for(int i = 1; i <= 4; i++) {
for(int j = 1; j <= 4; j++) {
cin >> v[i][j];
}
}
dfs(1, 1);
cout << ans;
return 0;
}