题目1 : 拆字游戏
时间限制:10000ms
单点时限:1000ms
内存限制:256MB
描述
小Kui喜欢把别人的名字拆开来,比如“螺”就可以拆成“虫田糸”,小Kui的语文学的不是很好,于是她决定使用编程的方式来解决这个问题。
给出一个01矩阵,1占据的部分即为需要拆的字,如果两个1分享一条边,那么它们连通。连通具有传递性,即如果a、b连通,b、c连通,则a、c连通。
连通的一系列1被看做可以拆出的一块,现在小Kui需要输出这些拆出的块(用一个01矩阵表示,并且要求矩阵的大小尽可能的小)。
为了确保输出的顺序尽可能的和书写的顺序一致,小Kui从每个块中选出最左上角的点(最左侧的点中,最靠上的)作为代表点,然后按照代表点从左到右(若相同则按从上到下)的顺序输出所有拆出的块。
输入
输入的第一行为两个正整数N、M,表示01矩阵的大小。
接下来N行,每行M个01字符,描述一个需要拆的字。
对于40%的数据,满足1<=N,M<=10。
对于100%的数据,满足1<=N,M<=500。
输出
按照代表点从左到右(若相同则按从上到下)的顺序输出所有拆出的块。
对于每个块,先输出其大小,然后用对应的01矩阵表示这个块。
额外的样例
样例输入 | 样例输出 |
11 17 00000000000000000 00001111111100000 00000000000000000111 001111111111111001 00000000100000000 00000010101110001 00000110100011000 00011100100001000 00000010100000000 00000001100000000 00000000000000000 |
7 13 1111111111111 0000001000000 0000001000000 0000001000000 0000001000000 0000001000000 0000011000000 3 4 0001 0011 1110 1 8 11111111 1 1 1 3 4 1110 0011 0001 |
样例输入
14 22
0000000000001111111100
0000000000001101101100
0000110000001111111100
0000110000001101101100
0111111110001111111100
0110110110000000000000
0110110110000011000000
0111111110001111111000
0000110000000001100000
0000110110001111111100
0111111111000111111000
0000000010001101101100
0000000000000001100000
0000000000000011100000
样例输出
10 9
000110000
000110000
111111110
110110110
110110110
111111110
000110000
000110110
111111111
000000010
5 8
11111111
11011011
11111111
11011011
11111111
8 8
00110000
11111110
00011000
11111111
01111110
11011011
00011000
00111000
题意分析:
1.题是什么?
其实就是给你一个长n宽m的01矩阵,现在要你把这个图中连通的1视作一块拆分输出出来,连通是用的四连通规则.
2.思路
做一个flag数组把像素图收录进去,然后二重循环依次判断flag[i][j]为1则从此点开始进行bfs,将此点及与此点连通的位置的flag值全部置为0,同时把经过的点记录到vector中,bfs的同时更新出此次dfs中经过的所有点的边界,此次bfs结束后,遍历vector把ans中对应的位置全部更新为1,输出对应边界内的ans,然后再次遍历vector把ans的所有位置更新为0并清空vector.继续寻找下一块
3.细节
小心对于输入的处理,c语言中读单字符要自己处理换行符,我是用getchar()过滤的,
其次一定要注意是按最左上方的1为准从左到右从上到下依次输出.
ac代码:
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace std;
const int maxn=505;
int path[4][2]={1,0,0,-1,-1,0,0,1};//四方向数组
char image[maxn][maxn];
char flag[maxn][maxn];
char ans[maxn][maxn];
vector<pair<int,int> > black;
int leftedge,rightedge,upedge,downedge;
void bfs(int x,int y,const int& n,const int& m){ //找出所有黑点存入black并更新出边界
flag[x][y]='0';
upedge=downedge=x,leftedge=rightedge=y;
black.clear();
black.push_back(make_pair(x,y));
for(int index=0;index<black.size();index++){
for(int i=0;i<4;i++){
int tx=black[index].first+path[i][0],ty=black[index].second+path[i][1];
if(0<=tx&&tx<n&&0<=ty&&ty<m&&flag[tx][ty]=='1'){
flag[tx][ty]='0';
if(tx>downedge) downedge=tx;
if(tx<upedge) upedge=tx;
if(ty>rightedge) rightedge=ty;
if(ty<leftedge) leftedge=ty;
black.push_back(make_pair(tx,ty));
}
}
}
}
void solve(){
int n,m;
scanf("%d%d",&n,&m);
getchar();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++) scanf("%c",&image[i][j]);
getchar();
}
//初始化,录入image到flag并初始ans画布
for(int i=0;i<n;i++) for(int j=0;j<m;j++){
if(image[i][j]=='0') flag[i][j]='0';
else if(image[i][j]=='1') flag[i][j]='1';
ans[i][j]='0';
}
for(int j=0;j<m;j++) for(int i=0;i<n;i++){
if(flag[i][j]=='1'){
bfs(i,j,n,m);
//渲染ans画布
for(int k=0;k<black.size();k++) ans[black[k].first][black[k].second]='1';
//输出ans画布
printf("%d %d\n",downedge-upedge+1,rightedge-leftedge+1);
for(int k=upedge;k<=downedge;k++){
for(int l=leftedge;l<=rightedge;l++) printf("%c",ans[k][l]);
printf("\n");
}
//清空ans画布
for(int k=0;k<black.size();k++) ans[black[k].first][black[k].second]='0';
}
}
}
int main(){
solve();
return 0;
}