1019 Separate the Animals (35 分)
解题思路:
差点就想放弃了,之前没写过类似的搜索,写了一个最暴力的,怎么剪枝优化都是T。
第一种思路——好想,但是复杂度过大,能拿23分:
DFS搜索每个空地的状态,对于每一个情况,judge判断是否合法,判断内容包括1.所有障碍是否4-connected;2.是否有动物会遇到一起;3.是否有h个hole。其中2和3用bfs跑连通分量可以一起实现。
第二种思路:
枚举每一个空地,在该位置放下一个障碍,然后开始DFS:每次都对已有的障碍都进行往四个方向进行扩展的进一步DFS。
显而易见,DFS的情况数巨大无比,同时这里使用状态压缩——将二维数组压缩为一维,然后对应位是障碍就是1,否则就是0,显然,这样就让每一个状态映射为一个唯一的二进制数,然后使用记忆化搜素,对于搜索过的状态直接return;这样还可以去重。
最后进行judge,与第一种思路的类似,还省去了第一部分的judge内容。
代码:
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define G 6.67430*1e-11
#define rd read()
#define pi 3.1415926535
using namespace std;
const ll mod = 1e9 + 7;
const int MAXN = 30000005;
const int MAX2 = 300005;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
ll fpow(ll a, ll b)
{
ll ans = 1;
while (b)
{
if (b & 1)ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
int n, m;
int k, h;
int vis[20][20];
string s[20];
int g[20][20];
int nx[4] = { 1,0,-1,0 };
int ny[4] = { 0,1,0,-1 };
pii fa[20][20];
bool judge()
{
memset(vis, 0, sizeof vis);
int hole = 0;
int animals = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
fa[i][j] = mp(i, j);
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (!vis[i][j] && g[i][j] != 2)
{
animals = 0;
int flag = 0;
queue<pii> q;
q.push(mp(i, j));
vis[i][j] = 1;
while (q.size())
{
auto p = q.front();
q.pop();
if (g[p.first][p.second] == 1)animals++;
if (p.first == 1 || p.first == n || p.second == 1 || p.second == m)
{
//走到了边界(即该情况的连通分量不是一个hole)
flag = 1;
}
for (int k = 0; k < 4; k++)
{
int x = nx[k] + p.first, y = ny[k] + p.second;
if (x >= 1 && x <= n && y >= 1 && y <= m && !vis[x][y] && g[x][y] != 2)
{
q.push(mp(x, y));
vis[x][y] = 1;
}
}
}
if (!flag)hole++;
if (animals >= 2)return false;
//多次遇到动物;
}
}
}
return hole == h;
}
int ans = 0;
bool valid(int x, int in)
{
return x >= 1 && x <= in;
}
unordered_map<ll, int> um;
void dfs(int i, int j, int now,ll value)
{
if (um[value])return;
um[value] = 1;
if (now == k)
{
if (judge())
{
ans++;
}
return;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (g[i][j] == 2)
{
for (int k = 0; k < 4; k++)
{
int x = nx[k] + i, y = ny[k] + j;
if (!g[x][y] && valid(x, n) && valid(y, m))
{
g[x][y] = 2;
dfs(x, y, now + 1, 1ll << (x * m + y) | value);
g[x][y] = 0;
}
}
}
}
}
}
signed main()
{
n = rd, m = rd, k = rd, h = rd;
int cnt = 0;
for (int i = 0; i < n; i++)
{
cin >> s[i];
for (int j = 0; j < s[i].size(); j++)
{
if (s[i][j] == 'O')
{
g[i + 1][j + 1] = 1;
cnt++;
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (!g[i][j])
{
g[i][j] = 2;
dfs(i, j, 1,1ll<<(i*m+j));
g[i][j] = 0;
}
}
}
cout << ans << endl;
return 0;
}