填涂颜色
如果左上角位置是0的话,我们可以轻松将所有在闭合曲线外的0标记。
为防止出现在左上角堆了一堆1的情况,可以在图像的周围包一层0,原来图像中暴露到边界的0肯定和这外围的0联通,从外围开始标记也能将原图像中在闭合曲线外的0标记。
输入时将两位下标都加入偏置,边界判断也要认为在外围的节点也在范围内。
原图像中是0且没有被标记为在闭合曲线外的地方即写为2的地方。
现在能保证左上角是0且从左上角可以到达所有原来在闭合圈之外的0,那将左上角入队。从队首的四个方向拓展四个节点,若拓展节点中有不超过边界——包括外围一圈0——且是0,又不被认为是在闭合圈内的0则将这个节点入队,将节点标记为已访问。拓展完后,将队首出队,再对更新后的队列的队首执行与之前的队列的队首相同的动作。
#include<iostream> #include<queue> int map_xy2lc[50][50];//(x,y)是闭合圈则map_xy2lc[x][y]是1,否则map_xy2lc[x][y]是0 int input() { int n; std::cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)//x=0和y=0都为外围的0保留,从(1,1)到(n,n)都填充有原图像,x=n+1和y=n+1仍为外围保留 std::cin>>map_xy2lc[i][j]; return n; } bool bound(int x,int y,int n) { return x>=0&&y>=0&&x<=n+1&&y<=n+1;//x能取到[0,n+1]而不是[1,n],y能取到[0,n+1]而不是[1,n] } bool map_xy2vis[50][50];//(x,y)是闭合圈外的0则map_xy2vis[x][y]是1 void output(int n) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++)//只输出原始图像的部分 { if(map_xy2lc[i][j]==0&&map_xy2vis[i][j]==0) { std::cout<<2; } else { std::cout<<map_xy2lc[i][j]; } std::cout<<" "; } std::endl(std::cout); } } int dx[]={-1, 1, 0, 0}; int dy[]={ 0, 0,-1, 1}; void walk(int n) { std::queue<std::pair<int,int>> Q; Q.push({0,0});//在外围的左上角而不在原图像内 map_xy2vis[0][0]=1; while(!Q.empty()) { std::pair<int,int> u=Q.front(); Q.pop(); for(int i=0;i<4;i++) { std::pair<int,int> v{u.first+dx[i],u.second+dy[i]}; if(bound(v.first,v.second,n)&&!map_xy2vis[v.first][v.second]&&map_xy2lc[v.first][v.second]==0) { Q.push(v); map_xy2vis[v.first][v.second]=1; } } } } int main() { int n=input(); walk(n); output(n); }