06-图1 列出连通集 (25 分)

06-图1 列出连通集 (25 分)

给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集。假设顶点从0到N−1编号。进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点。

输入格式:
输入第1行给出2个整数N(0<N≤10)和E,分别是图的顶点数和边数。随后E行,每行给出一条边的两个端点。每行中的数字之间用1空格分隔。

输出格式:
按照"{ v
​1
​​ v
​2
​​ … v
​k
​​ }"的格式,每行输出一个连通集。先输出DFS的结果,再输出BFS的结果。

输入样例:
8 6
0 7
0 1
2 0
4 1
2 4
3 5
输出样例:
{ 0 1 4 2 7 }
{ 3 5 }
{ 6 }
{ 0 1 2 7 4 }
{ 3 5 }
{ 6 }

评价:

我自己尝试了使用邻接表和邻接矩阵来建图,发现由于邻接表的无序插入,导致输出的时候顺序会比较乱,因此还是建议使用邻接矩阵来建图,不过两种方式返回的连通域都是一样的。
另外这个链接的博主写得不错
https://blog.csdn.net/weixin_40836227/article/details/89291550

#include <iostream>
#include<queue>
using namespace std;
typedef int weight;
typedef int Vertex;
typedef int datatype;
#define MaxN 10
queue<int> output;
/*------------------用邻接表建图-----------------------*/

struct LNode {
	Vertex v;
	weight w;
	LNode* NextNode;
	LNode():NextNode(NULL){}
};
typedef LNode* Llist;
/*这里定义了2种数据类型,一个是LHeadNode,一种是LHeadList*/
typedef struct LHeadNode {
	datatype data;
	Llist FirstLNode;
}LHeadList[MaxN];


struct LGraphNode {
	int nv;
	int ne;
	LHeadList LM;
};
typedef LGraphNode* LGraph;


LGraph buildLgraph(int N) {
	LGraph L = new LGraphNode;
	L->ne = 0;
	L->nv = N;
	for (int i = 0; i < L->nv; i++) {
		L->LM[i].FirstLNode=NULL;
	}
	return L;
}

void LInsertEdge(LGraph Lmap, Vertex v1, Vertex v2) {
	Lmap->ne++;
	Llist newnode = new LNode;
	newnode->v = v2;
	newnode->NextNode = Lmap->LM[v1].FirstLNode;
	Lmap->LM[v1].FirstLNode = newnode;

	Llist newnode2 = new LNode;
	newnode2->v = v1;
	newnode2->NextNode = Lmap->LM[v2].FirstLNode;
	Lmap->LM[v2].FirstLNode = newnode2;
}

/*这里这个LBFS由于插入的过程是随机的,因此输出的时候可能并不友好,达不到题目那个效果*/
void LBFS(LGraph Lmap, Vertex v, int visit[]) {
	int N = Lmap->nv;
	if (visit[v] != 1) {
		output.push(v);
		visit[v] = 1;
		cout << " " << v;
	}
	while (!output.empty()) {
		Vertex v2 = output.front();
		output.pop();
		/*邻接表的特点是只存储相连的节点,不相连的是没有信息的,因此链表上的都是相连的节点;另外还需要判断哪些是访问过的*/
		for (Llist Lptr = Lmap->LM[v2].FirstLNode; Lptr!= NULL; Lptr = Lptr->NextNode) {
			if (visit[Lptr->v] != 1) {//这个条件不能加在循环中,因为循环必须遍历所有的节点,但是是否加入是另外的一个问题
				output.push(Lptr->v);
				visit[Lptr->v] = 1;//标记为访问过了
				cout << " " << Lptr->v;
			}
		}
	}
}

void LDFS(LGraph Lmap, Vertex v, int visit[]) {
	int N = Lmap->nv;
	if (visit[v] != 1) {
		cout << " " << v;
		visit[v] = 1;
	}
	for (auto Lptr = Lmap->LM[v].FirstLNode; Lptr != NULL; Lptr = Lptr->NextNode) {
		if (visit[Lptr->v] != 1) {
			visit[Lptr->v] = 1;
			cout << " " << Lptr->v;
			LDFS(Lmap, Lptr->v, visit);
		}
	}
}


/*-----------------------------------------------------*/
/*1.用邻接矩阵建图*/
struct MGraphNode {
	int nv;
	int ne;
	weight G[MaxN][MaxN];
	datatype data[MaxN];
};

typedef MGraphNode* PtrToMGraph;
typedef PtrToMGraph MGraph;

/*矩阵建图*/
MGraph buildMgraph(int N) {
	MGraph Gmap= new MGraphNode;
	Gmap->nv = N;
	Gmap->ne = 0;
	for (int i = 0; i < Gmap->nv; i++) {
		for (int j = 0; j < Gmap->nv; j++) {
			Gmap->G[i][j] = 0;/*初始化为0,即没有连线*/
		}
	}
	return Gmap;
}

/*插入边*/
void InsertEdge(MGraph Gmap, Vertex v1, Vertex v2) {
	Gmap->ne++;
	Gmap->G[v1][v2] = 1;
	Gmap->G[v2][v1] = 1;
}



/*初始化访问记录*/
int visit[MaxN];
void reset(int a[],int N) {
	for (int i = 0; i < N; i++) {
		a[i] = 0;
	}
}

/*DFS从节点v开始遍历*/
void DFS(MGraph Gmap,Vertex v,int visit[]) {
	int N = Gmap->nv;
	if (visit[v] != 1) {
		visit[v] = 1;
		cout <<" "<<v;
	}
	for (int i = 0; i < N; i++) {
		if (Gmap->G[v][i] == 1&&visit[i]!=1) {/*如果有联通并且没有访问过*/
			DFS(Gmap, i, visit);/*这里其实有点像二叉树里面的遍历,只是二叉树里把每个遍历分为左右遍历,这里直接遍历了*/
		}
	}
}

void BFS(MGraph Gmap, Vertex v, int visist[]) {
	int N = Gmap->nv;
	if (visist[v] != 1) {
		visist[v] = 1;
		output.push(v);
	}

	while (!output.empty()) {
		Vertex v2 = output.front();
		output.pop();
		cout << " " << v2;
		for (int i = 0; i < N; i++) {
			if (Gmap->G[v2][i] == 1 && visist[i] != 1) {/*v2点周围如果是连通的而且没有被访问过,那么就将其加入队列并标记为访问过*/
				visist[i] = 1;
				output.push(i);
			}
		}
	}
}



int main() {
	int N, E;
	cin >> N>>E;
	MGraph Gmap = buildMgraph(N);
	Vertex v1, v2;
	for (int i = 0; i < E; i++) {
		cin >> v1 >> v2;
		InsertEdge(Gmap, v1, v2);
	}
	reset(visit, N);
	for (int i = 0; i < N; i++) {
		if (visit[i] != 1) {//通过循环来扫描连通域,如果扫描过一次连通域一定是访问过的了
			cout << "{";
			DFS(Gmap, i, visit);
			cout << " }" << endl;
		}
	}
	reset(visit, N);

	for (int i = 0; i < N; i++) {
		if (visit[i] != 1) {
			cout << "{";
			BFS(Gmap, i, visit);
			cout << " }" << endl;
		}
	}
	return 0;
}

/*
int main() {
	int N, E;
	cin >> N >> E;
	LGraph Lmap = buildLgraph(N);
	Vertex v1, v2;
	for (int i = 0; i < E; i++) {
		cin >> v1 >> v2;
		LInsertEdge(Lmap, v1, v2);
	}
	for (int i = 0; i < N; i++) {
		if (visit[i] != 1) {
			cout << "{";
			LDFS(Lmap, i, visit);
			cout << " }" << endl;
		}
	}
	reset(visit, N);
	for (int i = 0; i < N; i++) {
		if (visit[i] != 1) {
			cout << "{";
			LBFS(Lmap, i, visit);
			cout << " }" << endl;
		}
	}
	return 0;
}
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值