Description
在
N∗M
的棋盘上不重复的填1到
N∗M
,如果一个数字比周围的八个数字大,那么他就是一个山峰。现在告诉你所有山峰的位置,问你填数的方案数mod 12345678
Input
输入第一行两个数字
N
,
接下来
N
行,每行
1≤n≤4
,
m≤7
Output
仅一行,包含一个数字,为取模后的方案数。
Sample Input
1 3
.X.
Sample Output
2
HINT
并不是我写的题解
思路
这道题限制条件比较严格,山峰只能是给定的位置,其他的位置都不能是山峰。。。如果没有这个限制,那么直接状态压缩dp就可以了:从大到小枚举数字,设
fS,i
表示已经填了
i
个数字,填过的山峰为
代码
#include <cstdio>
#include <cstring>
const int maxn=4;
const int maxm=7;
const int maxtot=8;
const int dx[]= {1,1,1,0,0,-1,-1,-1};
const int dy[]= {1,0,-1,1,-1,1,0,-1};
const int mo=12345678;
int n,m,ans;
char map[maxn+1][maxm+1];
int x[maxn*maxn+1],y[maxn*maxn+1],can[maxn+1][maxm+1];
int f[1<<maxtot][maxn*maxm+1];
int in_range(int x,int y)//这个点是否在图的范围内
{
return (x<=n)&&(x>0)&&(y<=m)&&(y>0);
}
int x_around(int x,int y)//这个点周围是否有山峰
{
for(int i=0; i<8; i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(in_range(nx,ny))
{
if(map[nx][ny]=='X')
{
return 1;
}
}
}
return 0;
}
int calc()//计算至少有给定的点是山峰时的方案数
{
memset(f,0,sizeof f);
int tot=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(map[i][j]=='X')
{
tot++;
x[tot]=i;
y[tot]=j;
}
}
}
f[0][0]=1;
for(int s=0; s<1<<tot; s++)
{
memset(can,1,sizeof can);
for(int i=1; i<=tot; i++)
{
if(!(s&1<<(i-1)))
{
can[x[i]][y[i]]=0;
for(int j=0; j<8; j++)
{
int nx=x[i]+dx[j],ny=y[i]+dy[j];
if(in_range(nx,ny))
{
can[nx][ny]=0;
}
}
}
}
int cnt=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if(can[i][j])
{
cnt++;
}
}
}
for(int i=0; i<=cnt; i++)
{
if(f[s][i])
{
f[s][i+1]=(f[s][i+1]+f[s][i]*(cnt-i))%mo;
for(int j=1; j<=tot; j++)
{
if(!(s&1<<(j-1)))
{
f[s|1<<(j-1)][i+1]=(f[s|1<<(j-1)][i+1]+f[s][i])%mo;
}
}
}
}
}
return f[(1<<tot)-1][n*m];
}
int search(int x,int y,int k)
//寻找到了(x,y)这个点,找到答案后如果k=1那么就将答案加上这个值,否则减去这个值
{
if(x>n)
{
ans=(ans+k*calc())%mo;
return 0;
}
if(y>m)
{
search(x+1,1,k);
return 0;
}
search(x,y+1,k);
if((!x_around(x,y))&&(map[x][y]=='.'))
{
map[x][y]='X';
search(x,y+1,-k);
map[x][y]='.';
}
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
{
scanf("%s",map[i]+1);
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
if((map[i][j]=='X')&&x_around(i,j))
{
putchar('0');
putchar('\n');
return 0;
}
}
}
search(1,1,1);
printf("%d\n",(ans+mo)%mo);
return 0;
}