能成为局部极小值的位置最多同时存在8个,可以用状态压缩dp
把1~n*m依次填入矩阵,f[i][j]表示放完第i个数,状态为j的方案数
f[i][j]=f[i-1][j]*(p[j]-i+1)+f[i-1][k] //预处理p数组,p[i]表示状态为i时可以填数的位置有哪些
信心满满地wa了几发,发现显然会把某些不是答案的方案给统计进来,于是用容斥来排除那些不符合题目的方案
最后又wa了几(5)发(数组开错了)
#include<cstdio>
#include<cstring>
#define wyxsb 12345678
using namespace std;
int n,m,ans=0;
int p[1<<10],f[30][1<<10],node[10][2],vis[10][10];
int a[10][10];
char ch[10];
int calc()
{
memset(p,0,sizeof(p));
int tp=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(a[i][j]) node[++tp][0]=i,node[tp][1]=j;
for(int k=0;k<(1<<tp);++k)
{
memset(vis,0,sizeof(vis));
for(int j=1;j<=tp;++j)
if(!(k&(1<<j-1))) vis[node[j][0]][node[j][1]]=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
bool flag=1;
for(int x=-1;x<=1;++x)
for(int y=-1;y<=1;++y)
if(vis[i+x][j+y]) flag=0;
if(flag) ++p[k];
}
}
memset(f,0,sizeof(f));
f[0][0]=1;
for(int i=1;i<=n*m;++i)
for(int j=0;j<(1<<tp);++j)
{
if(p[j]>i-1) f[i][j]=(f[i][j]+f[i-1][j]*(p[j]-i+1))%wyxsb;
for(int k=1;k<=tp;++k)
if(j&(1<<k-1)) f[i][j]=(f[i][j]+f[i-1][j^(1<<k-1)])%wyxsb;
}
return f[n*m][(1<<tp)-1];
}
void dfs(int x,int y,int f)
{
if(x>n) {ans=(ans+((f&1)?-calc():calc()))%wyxsb;return;} //容斥
if(y>m) {dfs(x+1,1,f);return;}
dfs(x,y+1,f);
bool flag=1;
for(int i=-1;i<=1;++i)
for(int j=-1;j<=1;++j)
if(a[x+i][y+j]) return;
a[x][y]=1;
dfs(x,y+1,f+1);
a[x][y]=0;
}
int main()
{
scanf("%d %d",&n,&m);
int i,j;
for(i=1;i<=n;++i)
{
scanf("%s",ch);
for(j=0;j<m;++j)
a[i][j+1]=ch[j]=='X'?1:0;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(a[i][j])
for(int x=-1;x<=1;++x)
for(int y=-1;y<=1;++y)
if((x||y)&&a[i+x][j+y])
return puts("0"),0;
dfs(1,1,0);
printf("%d",(ans+wyxsb)%wyxsb);
return 0;
}