PIPIOJ1033

该博客介绍了如何通过BFS算法解决一个与字符矩阵拆分有关的问题。PiPi试图将一个01矩阵中的连通1部分拆分成单独的块,并按特定顺序输出。题目要求从每个块的最左上角开始,按从左到右、从上到下的顺序排列。博主提供了C++代码实现,该代码首先通过BFS遍历找到所有连通块,并更新答案矩阵,然后按照题目要求输出结果。

PIPIOJ1033拆字游戏:

题目描述:

PiPi喜欢把别人的名字拆开来,比如“螺”就可以拆成“虫田糸”,PiPi的语文学的不是很好,于是她决定使用编程的方式来解决这个问题。

给出一个01矩阵,1占据的部分即为需要拆的字,如果两个1分享一条边,那么它们连通。连通具有传递性,即如果a、b连通,b、c连通,则a、c连通。

连通的一系列1被看做可以拆出的一块,现在PiPi需要输出这些拆出的块(用一个01矩阵表示,并且要求矩阵的大小尽可能的小)。

为了确保输出的顺序尽可能的和书写的顺序一致,PiPi从每个块中选出最左上角的点(最左侧的点中,最靠上的)作为代表点,然后按照代表点从左到右(若相同则按从上到下)的顺序输出所有拆出的块。

输入:

多组数据。

输入的第一行为两个正整数N、M,表示01矩阵的大小。

接下来N行,每行M个01字符,描述一个需要拆的字。

对于40%的数据,满足1<=N,M<=10。

对于100%的数据,满足1<=N,M<=500。

输出:

按照代表点从左到右(若相同则按从上到下)的顺序输出所有拆出的块。

对于每个块,先输出其大小,然后用对应的01矩阵表示这个块。

解答:

实际上就是图的BFS,一道典型的搜索题。需要注意的是,规定了输出的顺序,所以在主函数中,查找还未被访问过的顶点是先列后行的顺序。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N=503;

char maze[N][N];//输入的01矩阵
bool vis[N][N];
struct Node{
	int row,col;//点的坐标 
}; 
int ans[N][N];
int sx,sy,ans_row,ans_col;
int dir[4][2]={1,0,0,-1,-1,0,0,1};
int n,m;//n行m列
bool check(int x,int y){
	if(maze[x][y]=='1'&&x>=0&&x<n&&y>=0&&y<m&&!vis[x][y])
		return true;
	else
		return false;
}
void bfs(int x,int y){//bfs的起点(x,y) 
	memset(ans,0,sizeof(ans));
	queue<Node> q;
	q.push({x,y});
	vis[x][y]=1;
	ans[x][y]=1;
	sx=x,sy=y,ans_row=x,ans_col=y;//sx,sy表示能包含当前块的最小矩阵左上角顶点在原图的坐标,ans_row和ans_col表示矩阵底边和右边在原图中的行号、列号
	while(q.size()){
		Node now=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			Node next;
			next.row=now.row+dir[i][0];
			next.col=now.col+dir[i][1];
			if(check(next.row,next.col)){
				q.push(next);
				ans[next.row][next.col]=1;
				vis[next.row][next.col]=1;
				if(sx>next.row)//更新答案矩阵的各项参数
					sx=next.row;
				if(sy>next.col)
					sy=next.col;
				if(ans_row<next.row)
					ans_row=next.row;
				if(ans_col<next.col)
					ans_col=next.col;
			}
		}
	}
}


int main(int argc, char** argv) {
	
	memset(vis,0,sizeof(vis));
	scanf("%d %d\n",&n,&m);//以防下一个scanf读入换行符,加上\n
	for(int i=0;i<n;i++){
		scanf("%s",maze[i]);
		
	} 
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			if(maze[j][i]=='1'&&!vis[j][i]){//如果还有顶点未被访问到
				sx=0,sy=0,ans_row=0,ans_col=0;
				bfs(j,i);
				printf("%d %d\n",ans_row-sx+1,ans_col-sy+1);
				for(int p=sx;p<=ans_row;p++){
					for(int q=sy;q<=ans_col;q++){
						printf("%d",ans[p][q]);
					}
					printf("\n");
				}
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值