版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/82763789
Description
有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。
给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。
Sample Input
3 2
X.
…
.X
Sample Output
60
有点奇妙…
首先数据范围小第一眼想到暴搜。
然后你可以发现最多只有8个X。
然后呢,就是一个DP (又被踩爆)
你设f[i][j]为填到第i个数,已知X的状态。
对于X你可以直接填,非X你要他周围的X都确定了才可填,然后你就转移即可。
然后你发现这样肯定是错的,于是你要容斥一下,因为最多只有8个X,大胆暴搜。
#include <cstdio>
#include <cstring>
using namespace std;
const int mod = 12345678;
const int dx[8] = {0, 1, 0, -1, 1, 1, -1, -1};
const int dy[8] = {1, 0, -1, 0, 1, -1, 1, -1};
char ss[10];
int id[5][10], num[1100], hh;
int ans, n, m, a[5][10], f[30][1100];
void dfs(int x, int y, int K) {
if(y == m + 1) y = 1, x++;
if(x == n + 1) {
memset(f, 0, sizeof(f));
memset(id, 0, sizeof(id));
memset(num, 0, sizeof(num));
f[0][0] = 1; int cnt = 0;
for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) if(a[i][j]) {
id[i][j] = ++cnt;
}
for(int i = 0; i < (1 << cnt); i++) {
for(int ii = 1; ii <= n; ii++) {
for(int jj = 1; jj <= m; jj++) {
if(a[ii][jj]) {
if((i >> id[ii][jj] - 1) & 1) num[i]++;
}
else {
bool bk = 0;
for(int k = 0; k < 8; k++) {
int nx = ii + dx[k], ny = jj + dy[k];
if(nx <= 0 || ny <= 0 || nx > n || ny > m) continue;
if(a[nx][ny] && !((i >> id[nx][ny] - 1) & 1)) bk = 1;
} if(!bk) num[i]++;
}
}
}
}
for(int i = 1; i <= n * m; i++) {
for(int j = 0; j < (1 << cnt); j++) if(f[i - 1][j]){
(f[i][j] += f[i - 1][j] * (num[j] - i + 1) % mod) %= mod;
for(int k = 0; k < cnt; k++) if(!(j >> k & 1)) {
(f[i][j | (1 << k)] += f[i - 1][j]) %= mod;
}
}
} if(K % 2 == 0) (ans += f[n * m][(1 << cnt) - 1]) %= mod, hh = f[n * m][(1 << cnt) - 1];
else (ans -= f[n * m][(1 << cnt) - 1]) %= mod;
return ;
}
if(a[x][y]) {dfs(x, y + 1, K); return ;}
bool bk = 0;
for(int k = 0; k < 8; k++) {
int nx = x + dx[k], ny = y + dy[k];
if(nx <= 0 || ny <= 0 || nx > n || ny > m) continue;
if(a[nx][ny]) {bk = 1; break;}
} if(!bk) a[x][y] = 1, dfs(x, y + 1, K + 1), a[x][y] = 0;
dfs(x, y + 1, K);
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%s", ss + 1);
for(int j = 1; j <= m; j++) if(ss[j] == 'X'){
a[i][j] = 1;
}
} dfs(1, 1, 0);
printf("%d\n", (ans + mod) % mod);
return 0;
}