BFS识别矩阵中的块数
题目描述:
给出一个m*n的矩阵,矩阵中的元素为0或1.称位置(x,y)与其上下左右四个位置是相邻的。如果矩阵中有若干个1相邻,则称这些1构成了一个块。求给定矩阵中的块数。
输入:
0 1 1 1 0 0 1
0 0 1 0 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 1 0
1 1 1 0 1 0 0
1 1 1 1 0 0 0
解题思路:对于这个问题,求解的基本思想是:枚举每一个位置的元素,如果为0,则跳过;如果为1则使用BFS查询与该位置相邻
的4个位置(前提是不出界),判断它们是否为1(如果某个位置为1,则应当继续查询与该位置相邻的4个位置,直到整个‘1’块
访问完毕)。为了防止走回头路,可以设置一个数据索引记录记录每个位置是否在BFS中已入队。
另外,我们可以设置增量数组来表示四个方向。
(这道题目也可以使用DFS解决,具体解法参见DFS求矩阵中的连通块数)
1 int x[] = {0,0,1,-1}; 2 int y[] = {1,-1,0,0};
参考代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <math.h> 4 #include <string.h> 5 #include <ctype.h> 6 7 #define maxn 100 8 #define MAX_SIZE 5 //最大队列长度+1 9 10 11 struct postion{ 12 int x; 13 int y; 14 }pos; 15 16 typedef struct postion ElemType; 17 typedef struct SqQueue{ 18 ElemType *base; //初始化的动态分配存储空间 19 int front; //头指针 20 int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置 21 }SqQueue; 22 23 24 int n,m; //矩阵大小n*m 25 int martix[maxn][maxn] = {0}; //01矩阵 26 int hashflag[maxn][maxn] = {0}; //记录位置x,y是否已经入队 27 28 int X[] = {0,0,1,-1}; 29 int Y[] = {1,-1,0,0}; 30 31 void BFS(int x,int y); 32 33 void InitQueue(SqQueue *Q); 34 35 int QueueEmpty(SqQueue *Q); 36 37 int EnQueue(SqQueue *Q,ElemType e); 38 39 ElemType DeQueue(SqQueue *Q); 40 41 int judge(int x,int y); 42 43 int main(){ 44 45 46 47 48 scanf("%d%d",&n,&m); //输入矩阵大小 49 50 for(int x=0;x<n;x++){ 51 for(int y=0;y<m;y++){ 52 scanf("%d",&martix[x][y]); 53 } 54 } 55 56 57 58 int ans = 0;//统计块数 59 60 for(int x=0;x<n;x++){ 61 for(int y=0;y<m;y++){ 62 //如果元素为1,且未入队 63 if(martix[x][y]==1&&hashflag[x][y]==0){ 64 ans++; 65 BFS(x,y); 66 } 67 } 68 } 69 70 printf("%d\n",ans); 71 return 0; 72 } 73 74 75 void BFS(int x,int y){ 76 //BFS函数访问x,y所在的块,将该块中所有“1”的hashflag设置为1 77 SqQueue Q; 78 InitQueue(&Q); 79 80 pos.x = x; 81 pos.y = y; 82 83 EnQueue(&Q,pos); 84 85 hashflag[x][y] = 1;//记录其已经入队 86 87 while(QueueEmpty(&Q)!=1){ 88 //printf("==============\n"); 89 ElemType top = DeQueue(&Q); //取出队首元素,出队 90 91 //printf("%d %d\n",top.x,top.y); 92 for(int i = 0;i<4;i++){ //循环四次得到四个位置 93 int newX = top.x+X[i]; 94 int newY = top.y+Y[i]; 95 if(judge(newX,newY)){ 96 //如果新位置需要访问 97 pos.x = newX; 98 pos.y = newY; 99 100 //入队 101 EnQueue(&Q,pos); 102 103 hashflag[newX][newY] = 1;//设置该位置已经入队了,防止走回头路 104 105 } 106 } 107 } 108 } 109 110 111 void InitQueue(SqQueue *Q){ 112 //构造一个空的队列 113 (*Q).base = (ElemType*)malloc(MAX_SIZE*sizeof(ElemType)); 114 if(!(*Q).base) { 115 exit(1); 116 } 117 Q->front = Q->rear = 0; 118 } 119 120 int QueueEmpty(SqQueue *Q){ 121 //若队列Q为空队列,则返回1;否则返回0 122 if(Q->front == Q->rear){ 123 //printf("-------------------------\n"); 124 return 1; 125 }else{ 126 return 0; 127 } 128 } 129 130 ElemType GetHead(SqQueue *Q){ 131 //若队列Q非空,则返回队列头元素 132 if(Q->front != Q->rear){ 133 return Q->base[Q->front]; 134 } 135 } 136 137 int EnQueue(SqQueue *Q,ElemType e){ 138 //进队元素e 139 if((Q->rear+1)%MAX_SIZE==Q->front){ 140 return 0; 141 } 142 Q->base[Q->rear] = e; 143 Q->rear = (Q->rear+1)%MAX_SIZE; 144 return 1; 145 146 } 147 148 149 ElemType DeQueue(SqQueue *Q){ 150 ElemType e; 151 if(Q->rear != Q->front){ 152 153 e = Q->base[Q->front]; 154 Q->front = (Q->front+1)%MAX_SIZE; 155 return e; 156 } 157 158 } 159 160 int judge(int x,int y){ //判断坐标x,y是否需要访问处理 161 //如果出界,返回0,不需要进一步访问 162 if(x>=n||x<0||y>=m||y<0){ 163 return 0; 164 } 165 //或者已经入队或者元素为0 166 if(martix[x][y] == 0||hashflag[x][y] == 1){ 167 return 0; 168 } 169 170 return 1; 171 }
为什么代码这么长?……,主要是因为我试着实现了一下队列的常见操作,毕竟复试的OJ上能不能用STL我还不知道呢。
所以自己顺便练练。