深圳大学计软《数据结构》实验11--图的最短路径和拓扑排序及应用

问题 A: DS图—图的最短路径(不含代码框架)

题目描述

给出一个图的邻接矩阵,输入顶点v,用迪杰斯特拉算法求顶点v到其它顶点的最短路径。

输入

第一行输入t,表示有t个测试实例

第二行输入顶点数n和n个顶点信息

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其它结点如果相连则为距离,无连接则为0,数据之间用空格

隔开。第四行输入v0,表示求v0到其他顶点的最短路径距离

以此类推输入下一个示例

输出

对每组测试数据,输出:

每行输出v0到某个顶点的最短距离和最短路径

每行格式:v0编号-其他顶点编号-最短路径值----[最短路径]。没有路径输出:v0编号-其他顶点编号–1。具体请参考示范数据

样例输入

2
5 0 1 2 3 4
0 5 0 7 15
0 0 5 0 0
0 0 0 0 1
0 0 2 0 0
0 0 0 0 0
0
6 V0 V1 V2 V3 V4 V5
0 0 10 0 30 100
0 0 5 0 0 0
0 0 0 50 0 0
0 0 0 0 0 10
0 0 0 20 0 60
0 0 0 0 0 0
V0

样例输出

0-1-5----[0 1 ]
0-2-9----[0 3 2 ]
0-3-7----[0 3 ]
0-4-10----[0 3 2 4 ]
V0-V1–1
V0-V2-10----[V0 V2 ]
V0-V3-50----[V0 V4 V3 ]
V0-V4-30----[V0 V4 ]
V0-V5-60----[V0 V4 V3 V5 ]

AC代码

#include <iostream>
using namespace std;

#define INFINITY_S 9999999


class Graph {
	int  VertexNum;
	string* Vertex;
	int** AdjMatrix;
	string* Path;
	int* Dest;
	string start;
public:
	Graph() { CreateGraph(); }
	void CreateGraph()
	{
		cin >> VertexNum;
		Vertex = new string[VertexNum];
		Dest = new int[VertexNum];
		Path = new string[VertexNum];
		AdjMatrix = new int* [VertexNum];
		for (int i = 0; i < VertexNum; i++) {
			AdjMatrix[i] = new int[VertexNum];
			cin >> Vertex[i];
		}
		for (int i = 0; i < VertexNum; i++)
			for (int j = 0; j < VertexNum; j++) {
				cin >> AdjMatrix[i][j];
				if (AdjMatrix[i][j] == 0)
					AdjMatrix[i][j] = INFINITY_S;
			}
	}

	void ShortestPath(string StartVexChar)
	{
		start = StartVexChar;
		int  StartVex, CurrentVex, MinDest;
		bool* Final = new bool[VertexNum];

		for (int i = 0; i < VertexNum; i++)
			if (Vertex[i] == StartVexChar) {
				StartVex = i;
				break;
			}


		for (int i = 0; i < VertexNum; i++) {
			Path[i].append(StartVexChar + " ");
			Dest[i] = INFINITY_S;
			if (AdjMatrix[StartVex][i] < INFINITY_S) {
				Dest[i] = AdjMatrix[StartVex][i];
				Path[i].append(Vertex[i] + " ");
			}
			Final[i] = false;
		}

		Dest[StartVex] = 0;
		Final[StartVex] = true;
		for (int i = 0; i < VertexNum - 1; i++) {
			MinDest = INFINITY_S;
			for (int j = 0; j < VertexNum; j++) {
				if (!Final[j]) {
					if (Dest[j] < MinDest) {
						CurrentVex = j;
						MinDest = Dest[j];
					}
				}
			}
			Final[CurrentVex] = true;
			for (int j = 0; j < VertexNum; j++) {
				if (!Final[j] && (MinDest + AdjMatrix[CurrentVex][j] < Dest[j])) {
					Dest[j] = MinDest + AdjMatrix[CurrentVex][j];
					Path[j] = Path[CurrentVex];
					Path[j].append(Vertex[j] + " ");
				}
			}
		}

		delete[] Final;
	}

	void print_shortest_path()
	{
		for (int i = 0; i < VertexNum; i++) {
			if (!Dest[i])
				continue;
			if (Dest[i] == INFINITY_S)
				cout << start << "-" << Vertex[i] << "--1" << endl;
			else
				cout << start << "-" << Vertex[i] << "-" << Dest[i] << "----[" << Path[i] << "]" << endl;
		}
	}

	~Graph() {
		for (int i = 0; i < VertexNum; i++)
			delete[] AdjMatrix[i];
		delete[]AdjMatrix;
		delete[]Vertex;
		delete[]Dest;
		delete[]Path;
	}

};

int main()
{
	int n;
	cin >> n;
	while (n--) {
		Graph graph;
		string start_node;
		cin >> start_node;
		graph.ShortestPath(start_node);
		graph.print_shortest_path();
	}
	return 0;
}

问题 B: 图综合练习–拓扑排序

题目描述

已知有向图,顶点从0开始编号,求它的拓扑有序序列。

拓扑排序算法:给出有向图邻接矩阵
1.逐列扫描矩阵,找出入度为0且编号最小的顶点v

2.输出v,并标识v已访问

3.把矩阵第v行全清0

重复上述步骤,直到所有顶点输出为止

–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求

输入

第一行输入一个整数t,表示有t个有向图

第二行输入n,表示图有n个顶点

第三行起,输入n行整数,表示图对应的邻接矩阵

以此类推输入下一个图的顶点数和邻接矩阵

输出

每行输出一个图的拓扑有序序列

样例输入

2
5
0 1 0 1 1
0 0 1 0 0
0 0 0 0 1
0 0 1 0 0
0 0 0 0 0
7
0 0 0 0 0 0 0
1 0 1 1 0 0 0
1 0 0 0 0 0 0
1 0 1 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 0 0 1 0 1 0

样例输出

0 1 3 2 4
4 6 5 1 3 2 0

AC代码

#include <iostream>
using namespace std;

#define INFINITY_S 1000  
class Graph {
	int  VertexNum;
	int** AdjMatrix;
public:
	Graph() { CreateGraph(); }
	void CreateGraph() {
		cin >> VertexNum;
		AdjMatrix = new int* [VertexNum];
		for (int i = 0; i < VertexNum; i++) {
			AdjMatrix[i] = new int[VertexNum];
			for (int j = 0; j < VertexNum; j++)
				cin >> AdjMatrix[i][j];
		}
	}

	void print_array() {
		for (int i = 0; i < VertexNum; i++) {
			for (int j = 0; j < VertexNum; ++j)
				cout << AdjMatrix[i][j] << " ";
			cout << endl;
		}
	}

	bool isOk(int index)
	{
		for (int i = 0; i < VertexNum; i++)
			if (AdjMatrix[i][index])
				return false;
		return true;
	}

	void TopSort() {
		bool* visited = new bool[VertexNum] {0};
		int rest = VertexNum;
		while (rest--)
		{
			for (int i = 0; i < VertexNum; i++)
				if (!visited[i] && isOk(i))
				{
					printf("%d ", i);
					visited[i] = 1;
					for (int j = 0; j < VertexNum; j++)
						if (AdjMatrix[i][j])
							AdjMatrix[i][j] = 0;
					break;
				}
		}
		cout << endl;
		delete[]visited;
	}

	~Graph()
	{
		for (int i = 0; i < VertexNum; i++)
			delete[]AdjMatrix[i];
		delete[]AdjMatrix;
	}
};

int main() {
	int n;
	scanf("%d", &n);
	while (n--)
	{
		Graph g;
		g.TopSort();
	}
	return 0;
}

问题 C: 追星

题目描述

城市总共有N座。yintama是右京女神的狂热粉,当他得知右京女神将要在城市N举办演唱会的时候,马上开始准备动身前往城市N。原本他可以直接乘飞机直达城市N,然而贫穷使他屈服,他必须选择总花费最少的那条路径。设总共有N座城市(2<=N<=1000),城市编号分别为1,2,3…N。M条航线(1<=M<=2000),每条航线连接两座城市,相互可以到达(无向的)。yintama目前在身在城市1,求最后yintama参加右京女神演唱会所需要的最少花费。(PS:重边考虑一下?)

输入

有多组输入。

第一行输入一个N、M,代表城市的总数,以及航线的总数。

接下来M行,每行输入三个数字u v w,代表城市u、v之间存在航线,机票花费为w。

输出

每行输出一个数,代表yintama参加右京女神演唱会所需的最少花费。

样例输入

5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100

样例输出

90

AC代码

#include <iostream>
using namespace std;

#define INFINITY_S 9999999

class Graph {
	int  VertexNum;
	int** AdjMatrix;
	int* Dest;
public:
	Graph() { CreateGraph(); }
	void CreateGraph() {
		cin >> VertexNum;
		Dest = new int[VertexNum];
		AdjMatrix = new int* [VertexNum];
		for (int i = 0; i < VertexNum; i++) {
			AdjMatrix[i] = new int[VertexNum];
			for (int j = 0; j < VertexNum; j++)
				AdjMatrix[i][j] = INFINITY_S;
		}
		int n;
		cin >> n;
		for (int i = 0; i < n; i++)
		{
			int v1, v2, cost;
			cin >> v1 >> v2 >> cost;
			if (cost < AdjMatrix[v1 - 1][v2 - 1])
				AdjMatrix[v1 - 1][v2 - 1] = AdjMatrix[v2 - 1][v1 - 1] = cost;
		}
	}

	void ShortestPath()
	{
		int  StartVex = 0, CurrentVex, MinDest;
		bool* Final = new bool[VertexNum];

		for (int i = 0; i < VertexNum; i++) {
			Dest[i] = INFINITY_S;
			if (AdjMatrix[StartVex][i] < INFINITY_S) {
				Dest[i] = AdjMatrix[StartVex][i];
			}
			Final[i] = false;
		}

		Dest[StartVex] = 0;
		Final[StartVex] = true;
		for (int i = 0; i < VertexNum - 1; i++) {
			MinDest = INFINITY_S;
			for (int j = 0; j < VertexNum; j++) {
				if (!Final[j]) {
					if (Dest[j] < MinDest) {
						CurrentVex = j;
						MinDest = Dest[j];
					}
				}
			}
			Final[CurrentVex] = true;
			for (int j = 0; j < VertexNum; j++) {
				if (!Final[j] && (MinDest + AdjMatrix[CurrentVex][j] < Dest[j])) {
					Dest[j] = MinDest + AdjMatrix[CurrentVex][j];
				}
			}
		}

		delete[] Final;
	}

	void print_shortest_cost()
	{
		cout << Dest[VertexNum - 1] << endl;
	}

	~Graph() {
		for (int i = 0; i < VertexNum; i++)
			delete[] AdjMatrix[i];
		delete[]AdjMatrix;
		delete[]Dest;
	}

};

int main()
{
	Graph graph;
	graph.ShortestPath();
	graph.print_shortest_cost();
	return 0;
}

问题 D: 关键路径-STL版

题目描述

给定有向图无环的边信息,求每个顶点的最早开始时间、最迟开始时间。

// 参考代码

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

class Vertex {
public:
    int indexNo;
    bool hasEnterQueue;
    int early;
    int later;

    Vertex(int indexNo) {
        this->indexNo = indexNo;
        this->hasEnterQueue = false;
        early = -1;
        later = 0x7FFFF;
    }
    void updateEarly(int parentEarly, int edgeValue) {
        int newEarly = parentEarly + edgeValue;
        if (newEarly > this->early)
            this->early = newEarly;
    }
    void updateLater(int childLater, int edgeValue) {
        int newLater = childLater - edgeValue;
        if (newLater < this->later)
            this->later = newLater;
    }
};


class Graph {
public:
    vector<Vertex> vertexes;
    vector<vector<int> > adjMat;
    int n;
public:
    void readVertexes() {
        //TODO: 将顶点数读入成员变量n
        
        //TODO: 从输入初始化vertexes数组
        int i=0;
        for(; i<n; ++i) {
            Vertex v(i);
            this->vertexes.push_back(v);
        }
        
        //为成员变量adjMat创建内存,赋初值
        for(i=0; i<n; ++i) {
            vector<int> row;
            int j=0;
            for(; j<n; ++j) {
                //TODO: 将0增加到row最后
            }
           //TODO: 将row增加到adjMat最后
        }
    }
    void readAdjMatrix() {
        //read the adjacent info into this->adjMat
        int edges;
        cin >> edges;
        int i=0;
        int s, t, w;  //s源顶点编号,t目的顶点编号,w边长
        for(; i<edges; ++i) {
            //TODO: 读入s,t,w,并将adjMat的第s行、第t列的值改为w.
        }
    }

    void updateEarly(int parentNo, queue<int>& earlyQue) {
        int parentEarly = vertexes[parentNo].early;  //读入父结点early值

        int j=0;
        for(; j<n; ++j) {
            int edgeValue = adjMat[parentNo][j];
            if (edgeValue == 0) continue;  //若父结点与结点j没有边相连,pass

            Vertex& child = vertexes[j];
            child.updateEarly(parentEarly, edgeValue); //更新子结点j的early信息

            if(!child.hasEnterQueue) {
                child.hasEnterQueue = true; //将子结点加入队列
                earlyQue.push(j);
            }
        }
    }
    void updateLater(int childNo, queue<int>& laterQue) {
        //TODO:
    }

    int getRoot() {
        //获取入度为0的顶点
        int j=0;
        for(; j<n; ++j) {
            int i=0;
            for(; i<n && adjMat[i][j] == 0; ++i);
            if (i>=n) return j; //j has not any in-edges.
        }
        return -1;  //表示没找到
    }
    int getLeaf() {
        //TODO: 获取出度为0的顶点
    }

    void printEarlyLater(bool isEarly) {
        int i=0;
        for(; i<n; ++i) {
            Vertex& v = vertexes[i];
            if (isEarly)
                cout << v.early << " ";
            else {
                cout << v.later << " ";
            }
        }
        cout << endl;
    }

    void findEarly() {
        //执行关键路径算法,求每个顶点的最早开始时间。
        int r = getRoot();
        Vertex& root = vertexes[r];
        root.hasEnterQueue = true;
        root.early = 0;

        queue<int> que;
        que.push(r);

        while(!que.empty()) {
            int p = que.front();
            que.pop();

            updateEarly(p, que);
        }

        printEarlyLater(true);
    }
    void clearEnterQueue() {
        int i=0;
        for(; i<n; ++i) {
            vertexes[i].hasEnterQueue = false;
        }
    }
    void findLater() {
        //TODO:调用clearEnterQueue,以清除每个顶点的hasEnterQueue=false
        //执行关键路径算法,求每个顶点的最迟开始时间。
    }

    void main() {
        readVertexes();
        readAdjMatrix();
        findEarly();
        findLater();
    }
};


int main() {
    int t=1;
    //cin >> t;
    while (t--) {
        Graph g;
        g.main();
    }
    return 0;
}

输入

第一行图的顶点总数

第二行边的总数

第三行开始,每条边的时间长度,格式为源结点 目的结点 长度

输出

第一行:第个顶点的最早开始时间

第二行:每个顶点的最迟开始时间

样例输入

9
12
0 1 3
0 2 10
1 3 9
1 4 13
2 4 12
2 5 7
3 6 8
3 7 4
4 7 6
5 7 11
6 8 2
7 8 5

样例输出

0 3 10 12 22 17 20 28 33
0 9 10 23 22 17 31 28 33

AC代码

#include<bits/stdc++.h>
using namespace std;

#define MAXCOST 9999999

class Time { public:int earlest, latest; };

class Graph {
	int VertexNum;
	int** AdjacencyMatrix;
	vector<Time>time;
	vector<int>in_degree;
	vector<int>top_sorted_vertex;
	void TopSort() {
		deque<int>q;
		for (int i = 0; i < VertexNum; i++)
			if (!in_degree[i])
				q.push_back(i);
		int pos = 0;
		while (q.size()) {
			int t = q.front();
			q.pop_front();
			for (int i = 0; i < VertexNum; i++)
				if (AdjacencyMatrix[t][i] != 0) {
					in_degree[i]--;
					if (in_degree[i] == 0)
						q.push_back(i);
				}
			top_sorted_vertex[pos] = t;
			pos++;
		}
	}

public:
	Graph() {
		cin >> VertexNum;
		time.resize(VertexNum);
		top_sorted_vertex.resize(VertexNum);
		in_degree.resize(VertexNum);
		for (int i = 0; i < VertexNum; i++)
			in_degree[i] = 0;
		AdjacencyMatrix = new int* [VertexNum];
		for (int i = 0; i < VertexNum; i++) {
			AdjacencyMatrix[i] = new int[VertexNum];
			for (int j = 0; j < VertexNum; j++)
				AdjacencyMatrix[i][j] = 0;
		}

		int n;
		cin >> n;
		for (int i = 0; i < n; i++) {
			int v1, v2, cost;
			cin >> v1 >> v2 >> cost;
			AdjacencyMatrix[v1][v2] = cost;
			in_degree[v2]++;
		}
		TopSort();
	}


	void get_time() {
		int k = top_sorted_vertex[0];
		time[k].earlest = 0;

		for (int i = 1; i < VertexNum; i++) {
			k = top_sorted_vertex[i];
			int max = 0;
			for (int j = 0; j < VertexNum; j++) {
				if (AdjacencyMatrix[j][k] != 0 && AdjacencyMatrix[j][k] + time[j].earlest > max)
					max = AdjacencyMatrix[j][k] + time[j].earlest;
			}
			time[k].earlest = max;
		}

		k = top_sorted_vertex[VertexNum - 1];
		time[k].latest = time[k].earlest;

		for (int i = VertexNum - 2; i >= 0; i--) {
			k = top_sorted_vertex[i];
			int min = MAXCOST;
			for (int j = 0; j < VertexNum; j++) {
				if (AdjacencyMatrix[k][j] != 0 && time[j].latest - AdjacencyMatrix[k][j] < min)
					min = time[j].latest - AdjacencyMatrix[k][j];
			}
			time[k].latest = min;
		}

		for (int i = 0; i < VertexNum; i++)
			cout << time[i].earlest << " ";
		cout << endl;
		for (int i = 0; i < VertexNum; i++)
			cout << time[i].latest << " ";
		cout << endl;
	}


	~Graph() {
		for (int i = 0; i < VertexNum; i++)
			delete[] AdjacencyMatrix[i];
		delete[] AdjacencyMatrix;
	}
};

int main() {
	Graph graph;
	graph.get_time();
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曹无悔

请支持我的梦想!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值