实验十 图的应用(第13-14周)

实验目的:

  掌握图的基本应用的实现。

实验内容与要求:

  请完成下列图的应用:

  ⑴求无向连通网的最小生成树;

  ⑵对有向图进行拓扑排序;

  ⑶求AOE网的关键路径;

⑷求单源点出发的最短路径。

四个题目分别创建了四个类,而在visual studio c++2019中,每个类都有 .h和 .cpp两个文件,如下图所示:

先贴主函数(图的应用.cpp)

#include"undirected_network.h"		//求无向连通网的最小生成树
#include"Topological_sorting.h"		//对有向图进行拓扑排序
#include"AOE_net.h"					//求AOE网的关键路径
#include"shortest_path.h"			//求单源点出发的最短路径
#include<iostream>
using namespace std;

//菜单
void show() {
	cout << "---图的应用---" << endl;
	cout << "1.求无向连通网的最小生成树" << endl;
	cout << "2.对有向图进行拓扑排序" << endl;
	cout << "3.求AOE网的关键路径" << endl;
	cout << "4.求单源点出发的最短路径" << endl;
	cout << "0.退出" << endl;
	cout << endl;
}

int main() {
	int n;
	show();
	while (1) {
		cin >> n;
		if (n == 0)break;
		else if (n == 1) {
			undirected_network u;
			u.create_net();
			u.find_minTree();
			u.print();
		}
		else if (n == 2) {
			Topological_sorting t;
			t.create();
			t.topology_sort();
		}
		else if (n == 3) {
			AOE_net a;
			a.create();
			a.aoe();
		}
		else if (n == 4) {
			shortest_path s;
			s.create();
			s.Floyd();
			s.print();
		}
		else {
			cout << "error";
		}
	}
}

求无向连通网的最小生成树

undirected_network.h

#include<iostream>
#include<vector>
using namespace std;
const int MAXX = 9999;

class undirected_network {
private:
	int vexnum = 0;		//顶点数
	int arcnum = 0;		//边数
	vector<char>vexs;
	int** g;			//邻接矩阵
	int** closedge;		//prim算法实现工具

public:
	void create_net();		//创建无向网
	void find_minTree();	//找最小生成树
	void print();			//输出最小生成树

	bool exist(char a, int& z) {		//判断该点是否在网中,若在则为真
		for (unsigned int i = 0; i < vexs.size(); i++) {
			if (a == vexs[i])z = i;
		}
		if (z == -1)return false;
		return true;
	}
};

undirected_network.cpp

#include "undirected_network.h"

void undirected_network::create_net()
{
	cout << "无向连通网的最小生成树" << endl;
	char a, b; int w;
	cout << "输入顶点数:";
	cin >> vexnum;
	g = new int* [vexnum];
	closedge = new int* [vexnum];
	for (int i = 0; i < vexnum; i++) {
		cout << "输入第" << i + 1 << "个顶点名称(例:a):";
		cin >> a;
		vexs.push_back(a);
	}
	for (int i = 0; i < vexnum; i++) {
		g[i] = new int[vexnum];
		for (int j = 0; j < vexnum; j++) {
			g[i][j] = MAXX;
		}
	}

	cout << endl;
	cout << "输入边数:";
	cin >> arcnum;
	int z1 = -1; int z2 = -1;
	for (int i = 0; i < arcnum; i++) {
		cout << "输入第" << i + 1 << "条边的信息(顶点1 顶点2 权重)(例:a b 1):";
		cin >> a >> b >> w;
		if (!exist(a, z1)) {
			cout << endl << "顶点" << a << "不存在" << endl;
			i--;
		}
		else if (!exist(b, z2)) {
			cout << endl << "顶点" << b << "不存在" << endl;
			i--;
		}
		else {
			if (g[z1][z2] != MAXX || g[z2][z1] != MAXX) {
				cout << endl << "该边已存在!";
				i--;
			}
			else {
				g[z1][z2] = w;
				g[z2][z1] = w;
			}
			z1 = -1; z2 = -1;
		}
	}
}

void undirected_network::find_minTree()
{
	//初始化二维数组
	for (int i = 0; i < vexnum; i++) {
		closedge[i] = new int[3];
		closedge[i][0] = 0;
		closedge[i][1] = g[0][i];
		closedge[i][2] = MAXX;
	}
	//取第一个顶点
	int k = 0;
	closedge[k][0] = 0;
	closedge[k][1] = 0;
	closedge[k++][2] = 0;

	int x = MAXX, y = -1;
	while (k != vexnum) {
		for (int i = 0; i < vexnum; i++) {
			if (closedge[i][1] != 0 && closedge[i][1] < x) {
				x = closedge[i][1];
				y = i;
			}
		}
		x = MAXX;
		//选出下一个顶点
		closedge[y][1] = 0;
		closedge[k++][2] = y;
		for (int j = 0; j < vexnum; j++) {
			if (g[j][y] < closedge[j][1]) {
				closedge[j][1] = g[j][y];
				closedge[j][0] = y;
			}
		}
		y = -1;
	}

}

void undirected_network::print()
{
	cout << endl << "最小生成树为:";
	for (int i = 0; i < vexnum; i++) {
		if (i != closedge[i][0]) {
			cout << vexs[i] << vexs[closedge[i][0]];
		}
		cout << endl;
	}
}

对有向图进行拓扑排序

Topological_sorting.h

#include<iostream>
#include<vector>
using namespace std;

class Topological_sorting {
private:
	struct ANode {
		int location;	//位置信息
		ANode* next;
	};
	struct VNode {
		string name;	//顶点信息
		ANode* first;	//头结点
		VNode() {
			first = new ANode;
			first->location = -1;
			first->next = NULL;
		}
	};

	vector<VNode>g;
	int vexnum = 0;		//顶点数
	int arcnum = 0;		//边数

public:
	void create();
	void topology_sort();		//拓扑排序

	bool exist(string a, int& x) {//判断顶点是否存在
		x = -1;
		for (unsigned int i = 0; i < g.size(); i++) {
			if (a == g[i].name)x = i;
		}
		if (x != -1)return true;
		return false;
	}
	bool connect(string a, string b, int x, int y) {//判断两个顶点之间是否有弧
		ANode* p = g[y].first->next;
		while (p != NULL) {
			if (p->location == x)return true;
			p = p->next;
		}
		return false;
	}
	bool arc_head(int x) {//判断该顶点是否为弧头
		ANode* p = g[x].first->next;
		if (p != NULL)return true;
		return false;
	}
};

Topological_sorting.cpp

#include "Topological_sorting.h"

void Topological_sorting::create()
{
	cout << "有向图进行拓扑排序" << endl;
	cout << "输入顶点数:";
	cin >> vexnum;
	for (int i = 0; i < vexnum; i++) {
		cout << "输入第" << i + 1 << "个顶点的名称(例:a):";
		VNode node;
		cin >> node.name;
		g.push_back(node);
	}
	cout << endl;
	cout << "输入弧数:";
	cin >> arcnum;
	string a, b;
	int x, y;
	for (int i = 0; i < arcnum; i++) {
		cout << "输入第" << i + 1 << "条弧(例:a b):";
		cin >> a >> b;
		if (!exist(a, x)) {
			cout << "顶点" << a << "不存在" << endl;
			i--;
		}
		else if (!exist(b, y)) {
			cout << "顶点" << b << "不存在" << endl;
			i--;
		}
		else {
			if (!connect(a, b, x, y)) {
				ANode* p = new ANode;
				p->location = x;
				p->next = g[y].first->next;
				g[y].first->next = p;
			}
			else {
				cout << "该弧已存在" << endl;
				i--;
			}
		}
	}

}

void Topological_sorting::topology_sort()
{
	cout << "有向图进行拓扑排序为:" << endl;

	int* v = new int[vexnum]();
	int x = -1;
	while (x != -2) {
		//找出下一个非弧头的顶点
		for (int i = 0; i < vexnum; i++) {
			if (!arc_head(i) && v[i] != 1) {
				x = i;
				v[i] = 1;
				break;
			}
		}
		//若没找到则跳出循环
		if (x == -1)x = -2;
		else {
			cout << g[x].name << " ";
			//取消选出顶点的弧
			for (int i = 0; i < vexnum; i++) {
				if (i != x) {
					ANode* p = g[i].first;
					while (p->next != NULL) {
						if (p->next->location == x) p->next = p->next->next;
						if (p->next != NULL)p = p->next;
					}
				}
			}
			x = -1;
		}
	}
}

求AOE网的关键路径

AOE_net.h

#include<iostream>
#include<vector>
using namespace std;

class AOE_net {
private:
	struct ANode {
		int location;	//位置信息
		int weight;		//权值
		ANode* next;
	};
	struct VNode {
		string name;	//顶点信息
		ANode* first;	//头结点
		VNode() {
			first = new ANode;
			first->location = -1;
			first->next = NULL;
		}
	};
	vector<VNode>v;
	int vexnum;		//顶点数
	int arcnum;		//边数

	int* vearly;
	int* vlate;
	int* aearly;
	int* alate;
	string* arc;

public:
	void create();
	void aoe();

	bool exist(string a, int& x) {//判断顶点是否存在
		x = -1;
		for (unsigned int i = 0; i < v.size(); i++) {
			if (a == v[i].name)x = i;
		}
		if (x != -1)return true;
		return false;
	}
	bool connect(string a, string b, int x, int y) {//判断两个顶点之间是否有弧
		ANode* p = v[y].first->next;
		while (p != NULL) {
			if (p->location == x)return true;
			p = p->next;
		}
		return false;
	}
};

AOE_net.cpp

#include "AOE_net.h"

void AOE_net::create()
{
	cout << "AOE网的关键路径" << endl;
	cout << "输入顶点数:";
	cin >> vexnum;
	for (int i = 0; i < vexnum; i++) {
		cout << "输入第" << i + 1 << "个顶点的名称(例:a):";
		VNode node;
		cin >> node.name;
		v.push_back(node);
	}
	vearly = new int[vexnum]();
	vlate = new int[vexnum]();

	cout << endl;
	cout << "输入弧数:";
	cin >> arcnum;
	string a, b;
	int x, y, w;
	for (int i = 0; i < arcnum; i++) {
		cout << "输入第" << i + 1 << "条弧(例:a b 1):";
		cin >> a >> b >> w;
		if (!exist(a, x)) {
			cout << "顶点" << a << "不存在" << endl;
			i--;
		}
		else if (!exist(b, y)) {
			cout << "顶点" << b << "不存在" << endl;
			i--;
		}
		else {
			if (!connect(a, b, x, y)) {
				ANode* p = new ANode;
				p->location = x;
				p->weight = w;
				p->next = v[y].first->next;
				v[y].first->next = p;
			}
			else {
				cout << "该弧已存在" << endl;
				i--;
			}
		}
	}
	aearly = new int[arcnum]();
	alate = new int[arcnum]();
	arc = new string[arcnum]();
}

void AOE_net::aoe() {
	//找各顶点的最早开始时间
	for (int i = 0; i < vexnum; i++) {
		ANode* p = v[i].first->next;
		if (p == NULL)vearly[i] = 0;
		else {
			int z = -1;
			while (p != NULL) {
				if (z < p->weight + vearly[p->location])z = p->weight + vearly[p->location];
				if (p != NULL)p = p->next;
			}
			vearly[i] = z;
		}
	}
	//找各顶点的最晚开始时间
	for (int i = 0; i < vexnum; i++)vlate[i] = -1;
	vlate[vexnum - 1] = vearly[vexnum - 1];
	for (int j = vexnum - 1; j >= 0; j--) {
		ANode* p = v[j].first->next;
		while (p != NULL) {
			if (vlate[p->location] == -1)vlate[p->location] = vlate[j] - p->weight;
			else if (vlate[p->location] > vlate[j] - p->weight)vlate[p->location] = vlate[j] - p->weight;
			if (p != NULL)p = p->next;
		}
	}
	//找关键路径
	int x = 0;
	for (int i = 0; i < vexnum; i++) {
		ANode* p = v[i].first->next;
		while (p != NULL) {
			string a = v[p->location].name + v[i].name;
			arc[x] = "边" + a;
			aearly[x] = vearly[p->location];
			alate[x++] = vlate[i] - p->weight;
			if (p != NULL)p = p->next;
		}
	}
	cout << endl;
	cout << "关键路径为:";
	//输出关键路径
	for (int i = 0; i < arcnum; i++) {
		if (aearly[i] == alate[i]) {
			cout << arc[i] << " ";
		}
	}
	cout << endl;
}

求单源点出发的最短路径

shortest_path.h

#include<iostream>
#include<vector>
using namespace std;
const int MAX = 9999;

class shortest_path {
private:
	int vexnum;		//顶点数
	int arcnum;		//边数
	struct rectangle {
		string** p;
		int** d;
	};
	int** g;
	string** p;
	rectangle* D;
	vector<string>vexs;

public:
	void create();		//创建
	void Floyd();		//计算最短路径
	void print();

	bool exist(string a, int& z) {		//判断该点是否在d中,若在则为真
		for (unsigned int i = 0; i < vexs.size(); i++) {
			if (a == vexs[i])z = i;
		}
		if (z == -1)return false;
		return true;
	}
	int min(int a, int b) {
		if (a < b)return a;
		return b;
	}
};

shortest_path.cpp

#include "shortest_path.h"

void shortest_path::create()
{
	cout << "单源点出发的最短路径" << endl;
	string a, b; int w;
	cout << "输入顶点数:";
	cin >> vexnum;
	g = new int* [vexnum];
	p = new string * [vexnum];
	for (int i = 0; i < vexnum; i++) {
		cout << "输入第" << i + 1 << "个顶点名称(例:a):";
		cin >> a;
		vexs.push_back(a);
	}
	for (int i = 0; i < vexnum; i++) {
		g[i] = new int[vexnum];
		p[i] = new string[vexnum];
		for (int j = 0; j < vexnum; j++) {
			if (i == j)g[i][j] = 0;
			else {
				g[i][j] = MAX;
			}
			p[i][j] = "#";
		}
	}

	cout << endl;
	cout << "输入边数:";
	cin >> arcnum;
	int z1 = -1; int z2 = -1;
	for (int i = 0; i < arcnum; i++) {
		cout << "输入第" << i + 1 << "条边的信息(顶点1 顶点2 权重)(例:a b 1):";
		cin >> a >> b >> w;
		if (!exist(a, z1)) {
			cout << endl << "顶点" << a << "不存在" << endl;
			i--;
		}
		else if (!exist(b, z2)) {
			cout << endl << "顶点" << b << "不存在" << endl;
			i--;
		}
		else {
			if (g[z1][z2] != MAX) {
				cout << endl << "该边已存在!";
				i--;
			}
			else {
				g[z1][z2] = w;
				p[z1][z2] = a + b;
			}
			z1 = -1; z2 = -1;
		}
	}
}

void shortest_path::Floyd()
{
	D = new rectangle[vexnum]();
	for (int i = 0; i < vexnum; i++) {
		D[i].d = new int* [vexnum];
		D[i].p = new string * [vexnum];
		for (int j = 0; j < vexnum; j++) {
			D[i].d[j] = new int[vexnum];
			D[i].p[j] = new string[vexnum];
		}
	}

	for (int i = 0; i < vexnum; i++)
		for (int j = 0; j < vexnum; j++) {
			D[0].d[i][j] = g[i][j];
			D[0].p[i][j] = p[i][j];
		}

	for (int i = 0; i < vexnum; i++) {
		for (int j = 0; j < vexnum; j++) {
			for (int k = 0; k < vexnum; k++) {
				if (j != k) {
					if (i == 0) {
						if (g[j][0] + g[0][k] >= g[j][k]) {
							D[0].d[j][k] = g[j][k];
						}
						else {
							D[0].d[j][k] = g[j][0] + g[0][k];
							if (p[j][k] == "#") {
								D[0].p[j][k] = "";
								D[0].p[j][k] = vexs[j] + vexs[0] + vexs[k];
							}
							else {
								string s1 = "";
								for (unsigned int x = 0; x < p[j][0].size() - 1; x++) {
									s1 += p[j][0][x];
								}
								unsigned y1 = vexs[0].size()-1;
								while (s1[s1.size() - 1] == vexs[0][y1]) {
									s1.pop_back();
									y1--;
									if (y1 > vexs[i].size() ||s1.size()==0)break;
								}
								unsigned int y2 = 0;
								string s2 = "";
								while (p[0][k][y2] == vexs[0][y2]) {
									y2++;
									if (y2 == vexs[0].size()||y2==p[0][k].size())break;
								}
								for (y2; y2 < p[0][k].size(); y2++) {
									s2 += p[0][k][y2];
								}
								D[0].p[j][k] = s1 + vexs[0] + s2;
							}
						}
					}
					else {
						if (D[i - 1].d[j][i] + D[i - 1].d[i][k] >= D[i - 1].d[j][k]) {
							D[i].d[j][k] = D[i - 1].d[j][k];
						}
						else {
							D[i].d[j][k] = D[i - 1].d[j][i] + D[i - 1].d[i][k];
							if (D[i].p[j][k] == "#") {
								D[i].p[j][k] = "";
								D[i].p[j][k] = vexs[j] + vexs[i] + vexs[k];
							}
							else {
								string s1 = "";
								for (unsigned int x = 0; x < D[i - 1].p[j][i].size(); x++) {
									s1 += D[i - 1].p[j][i][x];
								}
								unsigned int y1 = vexs[i].size() - 1;
								while (s1[s1.size() - 1] == vexs[i][y1]) {
									s1.pop_back();
									y1--;
									if (y1 > vexs[i].size()||s1.size()==0)break;
								}
								unsigned int y2 = 0;
								string s2 = ""; 
								while (D[i - 1].p[i][k][y2] == vexs[i][y2]) {
									y2++;
									if (y2 == vexs[i].size()||y2== D[i - 1].p[i][k].size())break;
								}
								for (y2; y2 < D[i - 1].p[i][k].size(); y2++) {
									s2 += D[i - 1].p[i][k][y2];
								}
								D[i].p[j][k] = s1 + vexs[i] + s2;		
							}
						}
					}
				}
			}
		}
		if (i != vexnum - 1) {
			for (int m = 0; m < vexnum; m++)
				for (int n = 0; n < vexnum; n++) {
					D[i + 1].d[m][n] = D[i].d[m][n];
					D[i + 1].p[m][n] = D[i].p[m][n];
				}
		}
	}

}

void shortest_path::print() {
	cout << endl;
	string a, b, c;
	int z1 = -1, z2 = -1;
	while (1) {
		cout << "是否查询单源点出发的最短路径(y or n):";
		cin >> a;
		if (a == "y") {
			cout << "输入两个顶点(例:a b):";
			cin >> b >> c;
			if (!exist(b, z1)) {
				cout << endl << "顶点" << b << "不存在";
			}
			else if (!exist(c, z2)) {
				cout << endl << "顶点" << c << "不存在";
			}
			else {
				if (D[vexnum - 1].d[z1][z2] != MAX||D[vexnum-1].p[z1][z2]!="#") {
					cout << "最短路径为:" << D[vexnum - 1].p[z1][z2] << endl;
					cout << "最短路径长为:" << D[vexnum - 1].d[z1][z2] << endl;
				}	
				else {
					cout << "无法到达" << endl;
				}
			}
		}
		else if (a == "n")break;
		else {
			cout << "error" << endl;
			char ch;
			while (1) {
				cin.get(ch);
				if (ch == '\n')break;
			}
		}
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值