PTA 列出连通集 --- 对于对称数组的保存

思路

这个题就是考验对于图的存储和遍历(BFS,DFS)操作

图的保存有邻接矩阵和邻接表,而在这个题中我使用的是邻接矩阵,在这个邻接矩阵也有两种保存的办法:

  1. 定义一个二维数组全部保存每个点的边,对于无向图,每个边要保存两边
  2. 定义一个一维数组,对于无向图,只保存方法1中二维数组的下三角矩阵(每个边保存一次)相对于第一种可以节省很大的空间。
  3. 对于第二种方法,两个结点之间的边在这个一维数组中的下标是在这里插入图片描述

错误代码

void DFS(int* G, int* visit, int N, int V) {
    
    
	visit[V] = 1;
	printf("%d ", V);
	//错误地方
	for (int i = V; i < N; i++) {
    
     //遍历每个临界点 对某个点的临界点来说,要按下三角矩阵遍历列
		if (G[i * (i + 1) / 2 + V] == 1 && visit[i] != 1) {
    
    
			DFS(G, visit, N, i);
		}
	}
}

void BFS(int* G, int* visit, int N, int V) {
    
    
	visit[V] = 1;
	printf("%d ", V);
	Enquee(V);
	while(!IsEmpty()) {
    
    
		V = Dequee();	//以下遍历V的临接点
		//错误地方
		for (int i = V; i < N; i++) {
    
     //遍历每个临接点 对某个点的临接点来说,要按下三角矩阵遍历列
			if (G[i * (i + 1) / 2 + V] == 1 && visit[i] != 1) {
    
    
				visit[i] = 1;
				printf("%d ", i);
				Enquee(i);
			}
		}
	}
}


解释错误

很奇怪,为什么错误代码还要发出来?
那是因为在错误代码中我的图的保存办法使用的第二种节约空间的办法,你会问使用了第二种方法那又怎样???
我们看一个案例:

10	7
1	4
1	3
1	5
4	2
6	7
6	9
7	8

这个案例中出现问题的是 4 2 这条边,你画出这个案例的图(我画的太丑就不画了),你会发现结点1 与 结点4 有条边, 结点4 与 结点2 有条边。

  • 换句话说:
    当我们遍历的时候应该先遍历到结点1,再遍历到结点4,最后才遍历到结点2
  • 然而 在第二种保存方法中当我们遍历一个结点的邻接矩阵时,是遍历下三角矩阵对应的列查找为1的值(比如遍历v3的邻接点,是从v3开始而非v0)这样就导致了当我们遍历结点4的邻接点时,是从结点4开始的,而没有查找结点2

正确代码

使用的第一种保存图的方法—用一个二维矩阵保存,这样查找某个结点的邻接矩阵时就简单的遍历对应的列即可,因为为二维,所以每次遍历都是从v0开始的

注意

在使用二维数组传参时,形参会使用数组指针 int(* G)[10]

#include <stdio.h>
#include <stdlib.h>

void DFS(int(* G)[10], int* visit, int N, int V) {
    
    
	visit[V] = 1;
	printf("%d ", V);
	for (int i = 0; i < N; i++) {
    
     //遍历每个临界点 对某个点的临界点来说,要按下三角矩阵遍历列
		if (G[i][V] == 1 && visit[i] != 1) {
    
    
			DFS(G, visit, N, i);
		}
	}
}

struct quee {
    
    
	int q[10];
	int front = 0;
	int rear = 0;
}Pq;

void Enquee(int V) {
    
    
	Pq.q[Pq.rear++] = V;
}

int Dequee() {
    
    
	return Pq.q[Pq.front++];
}

int IsEmpty() {
    
    
	if (Pq.front == Pq.rear)
		return 1;
	else
		return 0;
}

void BFS(int(* G)[10], int* visit, int N, int V) {
    
    
	visit[V] = 1;
	printf("%d ", V);
	Enquee(V);
	while(!IsEmpty()) {
    
    
		V = Dequee();	//以下遍历V的临接点
		for (int i = 0; i < N; i++) {
    
     //遍历每个临接点 对某个点的临接点来说,要按下三角矩阵遍历列
			if (G[i][V] == 1 && visit[i] != 1) {
    
    
				visit[i] = 1;
				printf("%d ", i);
				Enquee(i);
			}
		}
	}
}

int main() {
    
    
	int N, E;
	int a1, a2;
	scanf("%d %d", &N, &E);
	int G[10][10];
	for (int i = 0; i < E; i++) {
    
    
		scanf("%d %d", &a1, &a2);
		G[a1][a2] = 1;
		G[a2][a1] = 1;
	}
	//for (int i = 0; i < 44; i++) {
    
    
	//	printf("%d ", G[i]);
	//}
	int visit[10];
	for (int i = 0; i < N; i++) {
    
    
		visit[i] = 0;
	}
	for (int i = 0; i < N; i++) {
    
    
		if (visit[i] == 0) {
    
    
			printf("{ ");
			DFS(G, visit, N, i);
			printf("}\n");
		}
	}
	for (int i = 0; i < N; i++) {
    
    
		visit[i] = 0;
	}
	for (int i = 0; i < N; i++) {
    
    
		if (visit[i] == 0) {
    
    
			printf("{ ");
			BFS(G, visit, N, i);
			printf("}\n");
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_43779658/article/details/105182993