题解 P1162 【填涂颜色】

· · 题解

标准搜索题

题目描述: 由数字0组成的方阵中,有一任意形状闭合圈,闭合圈由数字1构成,围圈时只走上下左右4个方向。现要求把闭合圈内的所有空间都填写成2.例如:6×6的方阵(n=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

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。

首先看数据:n<=30 数据很小,搜索不会TLE,不用优化。

再看描述:方阵内只有一个闭合圈,圈内至少有一个0。

也就是说,除1与1包围的0以外,其他0都在外围

不用多说,搜索染色法,可以轻松拓展在一起的0。但这时,问题就来了:怎么搜外围? 众所周知,外围是有1的(如题目描述样例)

case1 :枚举外围:开循环枚举

蒟蒻专用写法 代码如下,枚举外围每个点,不难理解。

for(int i=1;i<=n;i++)if(f[i][1]==0)bfs(i,1);//第一列 for(int i=1;i<=n;i++)if(f[i][n]==0)bfs(i,n);//第n列 for(int i=1;i<=n;i++)if(f[1][i]==0)bfs(1,i);//第一行 for(int i=1;i<=n;i++)if(f[n][i]==0)bfs(n,i);//第n行

虽然可以,但是 有没有觉得太麻烦了点?

case2:围上一圈0

先拿样例来说:如果在外围围上一圈0,会怎样?

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

0 0 0 1 1 1 1 0

0 0 1 1 0 0 1 0

0 1 1 0 0 0 1 0

0 1 0 0 0 0 1 0

0 1 1 1 1 1 1 0

0 0 0 0 0 0 0 0

如果这样做,那么可以发现……由外圈开始,一定能搜到所有0! 于是,我们只需要短短的一行来搜索。

bfs(0,0);

上代码~

广搜代码

#include<bits/stdc++.h>//万能头,懒人专用 
using namespace std;
int f[32][32];
int dx[4]= {0,1,0,-1},dy[4]= {1,0,-1,0};//存储方向
int n;
queue<int>q;//使用stl队列
void bfs(int x,int y) {//广搜
    int x1,x2,y1,y2;//这里别学我开y1变量,有时候会被判断为一个函数y1,然后gg 
    q.push(x);//存储x(下同) 
    q.push(y);//存储y(下同) 
    f[x][y]=2;//染色(下同) 
    while(!q.empty()) {//队列不为空 
        x1=q.front();
        q.pop();
        y1=q.front();
        q.pop();//获得队头数据 
        for(int i=0; i<4; i++) {//向四个方向搜索
            x2=x1+dx[i];
            y2=y1+dy[i];//用变量,下文判断更方便 
            if(x2>=0&&x2<=n+1&&y2>=0&&y2<=n+1&&f[x2][y2]==0) { 
                q.push(x2);
                q.push(y2);
                f[x2][y2]=2;
            }//满足条件,入队
        }
    }
    return;
}
int main() {
    cin>>n;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++) {
            cin>>f[i][j];
        }
    bfs(0,0);//从(0,0)开始,一定能搜到外圈省去多余枚举外圈代码
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++)
            cout<<(f[i][j]==0?2:(f[i][j]==1?1:0))<<' ';//装B专用写法,意为如果为0输出2,否则如果为1输出1,否则输出0
        cout<<endl;//别忘记输出回车 
    }
    return 0;//好习惯 
}

深搜代码

void dfs(int x,int y) {
    f[x][y]=2;//染色
    for (int i=0; i<4; i++)
        if(x>=0&&x<=n+1&&y>=0&&y<=n+1&&f[x][y]==0)
            dfs(x+dx[i],y+dy[i]);
}

至于打哪种搜索,可以选择自己不熟练的进行练习(就像我不熟悉广搜,就打了个广搜代码)