像素放置
dfs+剪枝
思路:利用dfs填入0或者1,并利用数字进行判断,另外这一题数组要从1开始而不是0,这样在num方法中可以少了判断的操作
#include<iostream>
using namespace std;
//a数组存储输入的值,下划线则为-1
//ans数组存储填的01值
int a[15][15],ans[15][15];
bool flag=0;
int n,m;
int b[9][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,0},{0,1},{1,-1},{1,0},{1,1}};
//判断该数字格子周围九个点是否符合
bool num(int x,int y)
{
int res=0,big=a[x][y];
for(int i=0;i<9;i++)
{
int xx=x+b[i][0];
int yy=y+b[i][1];
if(ans[xx][yy]==1) res++;
if(res>big) return 0;
}
return res==big;
}
//检查某个点之前的数字点是否符合
bool checksub(int x,int y)
{
//假设到了x,y点,则x-2这一行及前面的九个格都已经填完
//细节:要从后往前遍历,否则会超时两个案例,因为其实前面有的已经判断过了,先判断后面的更快找到不符合的
for(int i=x-2;i>=1;i--)
{
for(int j=m;j>=1;j--)
{
if(a[i][j]==-1) continue;
if(!num(i,j)) return 0;
}
}
//x上一行y-2列及前面列周围九个格都已经填完
if(x>=2)
{
for(int j=y-2;j>=1;j--)
{
if(a[x-1][j]==-1) continue;
if(!num(x-1,j)) return 0;
}
}
return 1;
}
//检查所有格子是否符合
bool checkall()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i][j]==-1) continue;
if(!num(i,j)) return 0;
}
}
return 1;
}
void dfs(int x,int y)
{
//flag为1,表示已经找到唯一的解,直接返回
if(flag) return ;
if(!checksub(x,y)) return ;
//全部遍历完
if(x==n+1)
{
if(checkall())
{
flag=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
printf("%d",ans[i][j]);
}
printf("\n");
}
return ;
}
return ;
}
//遍历到最后一列
if(y==m)
{
ans[x][y]=1;
dfs(x+1,1);
ans[x][y]=0;
dfs(x+1,1);
return ;
}
ans[x][y]=1;
dfs(x,y+1);
ans[x][y]=0;
dfs(x,y+1);
return ;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char ch;
cin>>ch;
if(ch=='_') a[i][j]=-1;
else a[i][j]=ch-'0';
}
}
dfs(1,1);
return 0;
}