题目描述
由数字0组成的方阵中,有一任意形状闭合圈,闭合圈由数字11构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2,涂色前和涂色后的方阵如下:
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
输入格式
每组测试数据第一行一个整数n(1≤n≤30)
接下来n行,由0和1组成的n×n的方阵。
方阵内只有一个闭合圈,圈内至少有一个0。
输出格式
已经填好数字2的完整方阵。
输入输出样例
输入 #1
6
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 0 0 1
1 1 0 0 0 1
1 0 0 0 0 1
1 1 1 1 1 1
输出 #1
0 0 0 0 0 0
0 0 1 1 1 1
0 1 1 2 2 1
1 1 2 2 2 1
1 2 2 2 2 1
1 1 1 1 1 1
输入 #2
20
0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0
1 1 1 1 1 0 1 1 1 1 1 1 0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 1 1 1
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 1 1 0 0
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 1 1 1 1
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 1
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 1 1 1 1
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0
输出 #2
0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0 1 2 1 0 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0 1 2 1 0 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0 1 2 1 0 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0 1 2 1 0 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0 1 2 1 0 0 0 0 0 0
1 1 1 1 1 2 1 1 1 1 1 1 2 1 0 0 0 0 0 0
1 2 2 2 2 2 2 2 2 2 2 2 2 1 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 2 2 2 2 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 1 2 2 2 2 2 2 2 2 2 2 1
0 0 0 0 0 0 0 0 1 2 1 1 1 1 2 2 2 1 1 1
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 1 1 1 0 0
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 1 0 0 0 0
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 1 0 0 0 0
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 1 1 1 1 1
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 2 2 2 2 1
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 1 1 1 1 1
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 1 0 0 0 0
0 0 0 0 0 0 0 0 1 2 1 0 0 1 2 1 0 0 0 0
0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0
说明/提示
1<=n<=30
分析:遍历矩阵,如果当前位置(x,y)数字为0,就DFS搜索,如果能到达边界即(x<0||x>n||y<0||y>n),就把当前位置(x,y)以及走过的所有位置{(x1,y1),(x2,y2)...}用vis数组标记为1,代表这些位置都能达到边界。
我刚开始是用了记忆化搜索记忆了能达到边界的点,然后遍历整个矩阵,结果超时了。。。,有第四个测试点没过,也就是上面那个n=20的样例。
#include<bits/stdc++.h>
using namespace std;
int n;
int vis[33][33];
int mp[33][33];
int book[33][33];
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
bool dfs(int x,int y)
{
if(vis[x][y])
return true;
if(mp[x][y])
return false;
for(int i = 0; i<4; i++)
{
int ax = x+dx[i];
int ay = y+dy[i];
if(ax<0||ax>n||ay<0||ay>n)
{
vis[x][y]=1;
return true;
}
if(book[ax][ay]==0)
{
book[ax][ay]=1;
if(dfs(ax,ay))
{
vis[x][y]=1;
book[ax][ay]=0;
return true;
}
book[ax][ay]=0;
}
}
return false;
}
int main()
{
cin>>n;
for(int i = 0; i<n; i++)
{
for(int j = 0; j<n; j++)
{
scanf("%d",&mp[i][j]);
}
}
for(int i = 0; i<n; i++)
{
for(int j = 0; j<n; j++)
{
dfs(i,j);
}
}
for(int i = 0; i<n; i++)
{
for(int j = 0; j<n; j++)
{
if(j==n-1)
{
if(vis[i][j]==0&&mp[i][j]==0)
{
cout<<2<<endl;
}
else
{
cout<<mp[i][j]<<endl;
}
}
else
{
if(vis[i][j]==0&&mp[i][j]==0)
{
cout<<2<<" ";
}
else
{
cout<<mp[i][j]<<" ";
}
}
}
}
return 0;
}
后来我想,把出不去的点也记忆化,结果是错误的!!因为出不去的点存在这样一种情况
这样一个矩阵,我的程序会从第一个0(坐标为1,3)
由于我搜索的顺序是上下左右,所以从(1,3)开始搜索,向上不行,向下一直到最下面那个0(黄色的是走过的路)
之后在向左走
再向上走
最后会堵在这个红色的格的左边
因为我们的程序默认走过的路不能再走,所以程序会默认这个绿色的0走不出去就把他们标记为走不出去的位置了。
看了题解后,发现有一种更好的做法。具体做法:把矩阵整体移一下位置
这样从(0,0)开始搜索就能一下子把全部能到达边界的0标记了。
#include <bits/stdc++.h>
using namespace std;
int a[32][32],b[32][32];
int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,-1,1};//第一个表示不动,是充数的,后面的四个分别是上下左右四个方向
int n,i,j;
void dfs(int p,int q){
int i;
if (p<0||p>n+1||q<0||q>n+1||a[p][q]!=0) return;//如果搜过头或者已经被搜过了或者本来就是墙的就往回
a[p][q]=1;//染色
for (i=1;i<=4;i++) dfs(p+dx[i],q+dy[i]);//向四个方向搜索
}
int main(){
cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++){
cin>>b[i][j];//其实不拿两个数组也可以,不过我喜欢啦
if (b[i][j]==0) a[i][j]=0;
else a[i][j]=2;
}
dfs(0,0);//搜索 从0,0开始搜
for (i=1;i<=n;i++){
for (j=1;j<=n;j++)
if (a[i][j]==0) cout<<2<<' ';//如果染过色以后i,j那个地方还是0,说明没有搜到,就是周围有墙,当然就是被围住了,然后输出2
else cout<<b[i][j]<<' ';//因为被染色了,本来没有被围住的水和墙都染成了1,所以就输出b[i][j]
cout<<'\n';//换行
}
}