//广度优先搜索(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;
}