广度优先搜索

//广度优先搜索(breadth_first_search),类似于树的层次遍历。
/*
 *
 *从图中的某一个顶点v出发,在访问了v之后,依次访问v顶点未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,
 *并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问。直至图中所有的顶点都被访问过。
 *通俗来说:广度优先遍历搜索的过程就是以v为起始点,有近到远依次访问和v有路径相同且路径长度为1、2、3.....的顶点。
 */



#include "stdio.h"
#include "string.h"
#include "stdlib.h"



#define MAX_VERTEX_NUM 20//最大的顶点数

		

//边结点
typedef struct Edge {
	struct Edge *next;//指向下一个边的指针
	int index;//该边所依赖的顶点的位置
}Edge;

//顶点
typedef struct  {
	char name[10];//顶点的名字
	Edge * first;//指向依赖该顶点的第一条边	
}Vertex;

typedef struct  {
	int ver_num;//顶点的数
	int edge_num;//边数
	Vertex vertexs[MAX_VERTEX_NUM];
}Undigraph;

//根据名字找到顶点的位置
int get_location (Undigraph *ud,char * name) {
	int i;
	for (i = 0;i < ud->ver_num;i++) {
		if (0 == strcmp(name,ud->vertexs[i].name)) {
			return i;
		}
	}
	return -1;
}

//创建一个边
Edge* new_edge () {
	Edge *edge = (Edge*)malloc(sizeof(Edge));
	if (NULL == edge) {
		exit(-1);
	}
	edge->next = NULL;
	return edge;
}
//建立无向图
void create_undigraph (Undigraph * ud) {
	int k,i,j;
	char v1[10],v2[10];
	Edge *edge = NULL;
	scanf ("%d%d",&(ud->ver_num),&(ud->edge_num));//输入顶点数和边的数量
	//初始化顶点
	for (k = 0;k < ud->ver_num;k++) {
		scanf("%s",ud->vertexs[k].name);
		ud->vertexs[k].first = NULL;
	}
	//初始化边
	for (k = 0; k < ud->edge_num;k++) {
		scanf ("%s %s",v1,v2);
		i = get_location (ud,v1);
		j = get_location (ud,v2);

		edge = new_edge ();
		edge->index = j;
		edge->next = ud->vertexs[i].first;
		ud->vertexs[i].first = edge;

		edge = new_edge ();
		edge->index = i;
		edge->next = ud->vertexs[j].first;
		ud->vertexs[j].first = edge;
	}
}

//返回下标为v的顶点的第一个邻接点,有返回,没有返回NULL
Edge* first_adjacent_vertex (Undigraph *ud,int v) {
		if (v < 0 || v >= ud->ver_num) {
			return NULL;
		}
		return ud->vertexs[v].first;
}

//返回edge后的第一个邻接点,有返回,没有返回NULL
Edge* next_adjacent_vertex (Edge *edge ) {
		if (NULL == edge) {
			return NULL;
		}
		return edge->next;
}

//用于记录顶点是否被访问过的标志数组
int visited[MAX_VERTEX_NUM];


void breadth_first_search (Undigraph *ud) {
			int queue[MAX_VERTEX_NUM];
			int front,tail;
			int i;
			front = 0;
			tail = 1;
			memset (visited,0,sizeof(visited));	
			for (i = 0;i < ud->ver_num;i++) {
				if (0 == visited[i]) {
					printf ("%s",ud->vertexs[i].name);
					visited[i] = 1;
					queue[front] = i;
					while (front < tail) {
						int v = queue[front];
						Edge *edge =  first_adjacent_vertex (ud,v);
						while (NULL != edge) {
							if (0 == visited[edge->index]) {
								visited[edge->index] = 1;
								printf ("-%s",ud->vertexs[edge->index].name);
								queue[tail++] = edge->index;
							}
							edge =  next_adjacent_vertex (edge);
						}
						front++;
					}
				}
			}	
		

}
int main () {
	Undigraph ud;
	create_undigraph (&ud);
	breadth_first_search (&ud);
	return 0;
}

eg:

勘探油田
Description

某石油勘探公司正在按计划勘探地下油田资源。他们工作在一片长方形的地域中,首先将该地域划分为许多小正方形区域,然后使用探测设备分别探测每一块小正方形区域是否有油。若在一块小正方形区域中探测到有油,则标记为’@’,否则标记为’*’。如果两个相邻区域都为1,那么它们同属于一个石油带,一个石油带可能包含很多小正方形区域,而你的任务是要确定在一片长方形地域中有多少个石油带。所谓相邻,是指两个小正方形区域上下、左右、左上右下或左下右上同为’@’。

Input

输入数据将包含一些长方形地域数据,每个地域数据的第一行有两个正整数m和n,表示该地域为m*n个小正方形所组成,如果m为0,表示所有输入到此结束。否则,后面m(1≤m≤100)行数据,每行有n(1≤n≤100)个字符,每个字符为’@’或’*’,表示有油或无油。每个长方形地域中,’@’的个数不会超过100。

Output

每个长方形地域,输出油带的个数,每个油带值占独立的一行。油带值不会超过100。

Sample Input

3 5
*@*@*
**@**
*@*@*
0 0

Sample Output

1

代码如下:

#include "stdio.h"
#include "string.h"
#define MAXN (100+10)
char matrix[MAXN][MAXN];
int visited[MAXN][MAXN];
int queue[MAXN];
int dir[8][2] = {//8个方向
	{-1,-1},//左上
	{-1,0},//上
	{1,0},//下
	{-1,1},//右上
	{0,-1},//左
	{0,1},//右
	{1,-1},//左下
	{1,1}//右下
};

int isRightRange (int newX,int newY,int m,int n) {
	if (newX < 0 || newX >= m || newY < 0 || newY >= n || matrix[newX][newY] == '*' || visited[newX][newY] == 1) {
		return 0;
	}
	return 1;
}

void bfs (int i,int j,int m,int n) {
	int z = i * n + j;
	int x,y,t,newX,newY,newZ;
	int ans;
	int front,tail;
	front = tail = 0;
	queue[tail++] = z;
	visited[i][j] = 1;
	while (front < tail) {
		t = queue[front];
		x = t / n;
		y = t % n;
		for (i = 0;i < 8;i++) {
			 newX = x + dir[i][0];
			 newY = y + dir[i][1];
			 ans = isRightRange (newX,newY,m,n);
			if (ans) {
				visited[newX][newY] = 1;
				newZ = newX * n + newY;
				queue[tail++] = newZ;
			}
		}
		front++;	
	}
}
int main () {
	int m,n,t;
	int i,j;
	int count;
	while (scanf ("%d%d",&m,&n),m != 0 && n != 0) {
		for (i = 0; i < m;i++) {
			getchar();
			for (j = 0;j < n;j++) {
				scanf ("%c",&matrix[i][j]);		
			}
		}
		count = 0;
		memset(visited,0,sizeof(visited));
		for (i = 0;i < m;i++) {
			for (j = 0;j < n;j++) {
				if (matrix[i][j] == '@' && visited[i][j] == 0) {
						bfs (i,j,m,n);
						count++;
				}
			}
		}
		printf ("%d\n",count);
	}
	return 0;
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值