2021-04-13

题目描述

由数字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';//换行
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值