数据结构 第七章 图

Part1

练习3
在这里插入图片描述
思路:利用栈进行遍历访问,若栈空则形成一个连通子图
非递归遍历算法思想:
(1)访问一个顶点,记录被访问;其所有未被访问的邻接顶点入栈
(2)若栈空,退出;否则,栈中一顶点出栈
(3)若顶点已被访问,则转(2);否则,转(1)

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 110;
stack<int>s;
struct Mgraph {
	int map[MAX_N][MAX_N];
	int vexnum;
}G;
int visited[MAX_N];
int main()
{
    cin >>G.vexnum;
	int i, j, v;
	for (i = 1; i <= G.vexnum; i++)
		for (j = 1; j <= G.vexnum; j++)
			cin >> G.map[i][j];
	int cnt = 0, find = 0;
	for (int i = 1; i <= G.vexnum; i++)
		if (visited[i] == 0) {//若该顶点没被访问
			v = i;
			while (1) {
				find = 0;
				visited[v] = 1;//标记一顶点
				for (j = 1; j <= G.vexnum; j++) //所有未标记的邻接顶点入栈
					if (G.map[v][j] == 1 && visited[j] == 0)
						s.push(j);
				do {
					if (s.empty()) {//如果栈空则退出
						cnt++; find = 1; break;
					}
					v = s.top(); s.pop();//否则栈中一顶点出栈
				} while (visited[v] == 1);//如果顶点未被访问过,退出循环,访问这个顶点
			}
			if (find == 1)break;//退出外层循环
		}
	cout << cnt;
	return 0;
}

递归:

#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 110;
struct MGraph {
	int map[MAX_N][MAX_N];
	int vexnum;
}G;
int visited[MAX_N];
void DFS(int v){//遍历一个连通图
	visited[v] = 1;
	for (int j = 1; j <= G.vexnum; j++)
		if (G.map[v][j] && !visited[j])
			DFS(j);
}
int main()
{
	cin >> G.vexnum;
	for (int i = 1; i <= G.vexnum; i++)
		for (int j = 1; j <= G.vexnum; j++)
			cin >> G.map[i][j];
	int cnt = 0;
	for (int i = 1; i <= G.vexnum; i++)//遍历图中所有连通子图
		if (!visited[i]){
			DFS(i);//遍历一个连通子图
			cnt++;//得到一个连通子图
		}
	cout << cnt;
	return 0;
}

Part2

练习1
在这里插入图片描述
思路:利用普利姆算法。
普利姆算法:从U={u0}, TE={}开始,在所有u∈U, v∈V-U的边(u,v)∈E中找到一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直至U=V为止

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 100;
const int MAX_NUM = 10000;
struct Graph {//邻接矩阵
	int GMap[MAX_N][MAX_N];
	int vexnum;
}G;
vector<int>u;//存放U中顶点
int main()
{
	cin >> G.vexnum;
	int i, j;
	for (i = 1; i <= G.vexnum; i++)	
		for (j = 1; j <= G.vexnum; j++)	
			cin >> G.GMap[i][j];
	int min, sign, sum = 0;
	u.push_back(0); u.push_back(1);//顶点1进U
	while (u.size() <= G.vexnum) {
		min = MAX_NUM;
		for (i = 1; i < u.size(); i++) 
			for (j = 1; j <= G.vexnum; j++)
				if (G.GMap[u[i]][j]!=0&&G.GMap[u[i]][j] < min) {
					min = G.GMap[u[i]][j]; sign = j;
				}
		G.GMap[--i][sign] = 0; G.GMap[sign][i] = 0;//将遍历过的图置0,防止重复遍历
		sum += min;
		u.push_back(sign);//将顶点入U
	}
	cout << sum;
	return 0;
}

练习2
在这里插入图片描述
在这里插入图片描述
思路:利用迪杰斯特拉算法求源点到其余各点的最短路径
迪杰斯特拉算法:按路径长度递增的次序产生你最短路径。下一条最短路径或者是弧(v,x),或者是中间只经过S中的顶点而最后到达顶点x的路径。

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 25;
const int MAX_NUM = 10000;
struct Graph {//邻接矩阵
	int GMap[MAX_N][MAX_N];
	int vexnum;
}G;
int final[MAX_N],D[MAX_N];//final[i]为1,i顶点在S中
int main()
{
	cin >> G.vexnum;
	int i, j;
	for (i = 1; i <= G.vexnum; i++)	
		for (j = 1; j <= G.vexnum; j++)	
			cin >> G.GMap[i][j];
	for (i = 1; i <= G.vexnum; i++)
		for (j = 1; j <= G.vexnum; j++)
			if (j != i && G.GMap[i][j] == 0)
				G.GMap[i][j] = MAX_NUM;//设没有路径的两顶点间距离为MAX_NUM
	final[1] = 1;//第一个顶点入S
	for (i = 2; i <= G.vexnum; i++) {//初始化D数组
		D[i] = G.GMap[1][i];
	int min,v;
	for (i = 2; i <= G.vexnum; i++) {//其余n-1个顶点
		min = MAX_NUM;//当前所知离v1最近的距离
		for(j=1;j<=G.vexnum;j++)//得到从1出发的最短路径的终点v
			if (!final[j]&& D[j] < min){
					min = D[j];v = j;
				}
		final[v] = 1;//顶点v入S
		for(j=1;j<=G.vexnum;j++)//修改从v出发到集合V-S上任一顶点vk可达最短路径长度
			if (!final[j] && min + G.GMap[v][j] < D[j]) 
				D[j] = min + G.GMap[v][j];
	}
	if (D[G.vexnum] == MAX_NUM)cout << -1;//没有路径
	else cout << D[G.vexnum];
	return 0;
}

佛洛依德算法(每一对顶点之间的最短路径):
d[N][N]为带权路径长,p[N][N][N],若p[i][j][k]=1,则k是从i到j求得的最短路径上的顶点

int d[N][N], p[N][N][N];//数据过大时,可把三维数组改为结构体数组
void floyd() {
	int i, j, k, t;
	for(i=1;i<=G.vexnum;i++)//各对顶点之间初始已知路径及距离
		for (j = 1; j <= G.vexnum; j++) {
			d[i][j] = G.map[i][j];
			if (d[i][j] < N) {//从i到j有直接路径
				p[i][j][i] = 1; p[i][j][j] = 1;
			}
		}
	for(k=1;k<=G.vexnum;k++)
		for(i=1;i<=G.vexnum;i++)
			for(j=1;j<=G.vexnum;j++)
				if (d[i][k] + d[k][j] < d[i][j]) {//从i经k到j的一条路径更短
					d[i][j] = d[i][k] + d[k][j];
					for (t = 1; t <= G.vexnum; t++)//更新路径
						p[i][j][t] = p[i][k][t] || p[k][j][t];
				}
}

练习3
在这里插入图片描述
在这里插入图片描述
思路:利用拓扑排序,如果排序序列中数字个数小于n,则有环
拓扑排序:
(1)在有向图中选一个没有前驱的顶点输出
(2)从图中删除该顶点和所有以它为尾的弧

#include<bits/stdc++.h>
using namespace std;
const int MAX_N = 25;
typedef long long ll;
struct Graph {//邻接矩阵
	int GMap[MAX_N][MAX_N];
	int vexnum;
}G;
stack<int>s;//存储入度为0的顶点
int degree[MAX_N];
int main()
{
	cin >> G.vexnum;
	int i, j;
	for (i = 1; i <= G.vexnum; i++)	
		for (j = 1; j <= G.vexnum; j++)	
			cin >> G.GMap[i][j];
	for (i = 1; i <= G.vexnum; i++)	//逐列计算各顶点入度
		for (j = 1; j <= G.vexnum; j++)	
			if (G.GMap[j][i] == 1)	
				degree[i]++;
	for (i = 1; i <= G.vexnum; i++)//入度为0的顶点入栈
		if (degree[i] == 0)	
			s.push(i);
	int cnt = 0;//对已排序顶点计数
	while (!s.empty()) {
		i = s.top(); s.pop(); cnt++;//顶点出栈
		for (j = 1; j <= G.vexnum; j++) {
			if (i == j)continue;
			if (G.GMap[i][j] == 1) {//i号顶点的每个邻接顶点入度-1
				degree[j]--;
				if (degree[j] == 0)s.push(j);//入度为0入栈}
			}
		}
	}
	if (cnt < G.vexnum)cout << "YES";
	else cout << "NO";
	return 0;
}

拓扑排序(关键路径中的):用栈t逆序存放拓扑序列

void topological_order() {
	int j;
	for (int i = 1; i <= G.vexnum; i++)
		for (int j = 1; j <= G.vexnum; j++)
			if (G.map[j][i])
				indegree[i]++;
	for (int i = 1; i <= G.vexnum; i++)
		if (!indegree[i])
			s.push(i);
	int cnt = 0,dut;
	while (!s.empty()) {
		j = s.top(); s.pop(); t.push(j); cnt++;
		for(int k=1;k<=G.vexnum;k++)
			if (G.map[j][k]) {
				indegree[k]--;
				if (!indegree[k])s.push(k);
				dut = G.map[j][k];
				if (ve[j] + dut > ve[k])//ve[k]=max{ve[j]+dut}
					ve[k] = ve[j] + dut;
			}
	}
}

关键路径:

void critical_path() {
	topological_order();
	int j,k,dut;
	memset(vl, ve[G.vexnum], sizeof(int));
	while (!t.empty()) {
		j = t.top(); t.pop();
		for(k=1;k<=G.vexnum;k++)
			if (G.map[j][k]) {
				dut = G.map[j][k];
				if (vl[k] - dut < vl[j])//vl[j]=min{vl[k]-dut}
					vl[j] = vl[k] - dut;
			}
	}
	int ee, el;
	for(j=1;j<=G.vexnum;j++)
		for(k=1;k<=G.vexnum;k++)
			if (G.map[j][k]) {
				dut = G.map[j][k];
				ee = ve[j]; el = vl[k] - dut;//计算关键路径
				if (ee == el)cout << j << ' ' << k << endl;
			}
}
发布了99 篇原创文章 · 获赞 44 · 访问量 5527

猜你喜欢

转载自blog.csdn.net/weixin_44413191/article/details/102868299