图的最短路径-STL版

输入
第一行输入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 ]

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

//定义无穷大距离
#define MAX_DIS 0x7FFFFF

class Vertex {
	public:
		int indexNo;   //顶点索引号:顶点位于顶点数组的下标取值[0,n)
		string label;  //顶点的标签
		int distance;  //顶点到源点的距离
		bool isVisited; //顶点是否已经按Dijkstra算法处理过(不用再处理了)
		vector<int> path; //顶点到源点的路径

		Vertex(int indexNo, const string& label="", int distance=MAX_DIS) {
			this->label = label;
			this->distance = distance;

			this->indexNo = indexNo;
			this->isVisited = false;
		}
		void updatePath(const vector<int>& prePath) {
			this->path = prePath;   //复制源结点到前一个结点的路径
			this->path.push_back(this->indexNo);     //TODO: 增加本结点到路径数组this->path中
		}

		//打印输出本结点信息
		//输入:顶点数组(供查询用)、源结点索引号(顶点数组下标)
		void displayPath(vector<Vertex>& vertexes, int sourceNo) {

			//0-1-5----[0 1 ]
			cout << vertexes[sourceNo].label; //0
			cout << "-";
			cout << this->label; //1

			cout << "-";
			if (this->distance >= MAX_DIS) {
				cout << "-1\n";                        //TODO: 如果源结点到本结点距离无穷大,则(按题目要求)输出-1
				return;
			}
			cout << this->distance; //5
			cout << "----";

			cout << "[";
			int i=0;
			int size = this->path.size();
			for(; i<size; ++i) {
				cout << vertexes[path[i]].label <<" ";                    //TODO: 如果源结点到本结点距离<无穷大,则(按题目要求)输出标签和空格
			}
			cout << "]";
			cout << endl;
		}
};

//打印顶点信息,供调试用
ostream& operator<<(ostream& out, const Vertex& v) {
	out << v.indexNo << "_" << v.label << ": " << v.distance << " ";
	return out;
}

/
class Graph {
	public:
		vector<Vertex> vertexes; //顶点数组:存放顶点信息
		vector<vector<int> > adjMat;  //邻接矩阵:存放每对结点距离,若1对结点i,j之间无边相连,则adjMat[i,j]=0
	public:

		void printVertexes() {  //用于调试
			int i=0;
			int n = vertexes.size();
			for(; i<n; ++i) {
				cout << vertexes[i];
			}
			cout << endl;
		}

		int getNo(string& label) {
			//TODO: 遍历顶点数组vertexes,找到标签属性=label的顶点索引号
			//并返回。
			int i=0;
			int n = vertexes.size();
			for(; i < n; i++) {
				if(vertexes[i].label == label) {
					return vertexes[i].indexNo;
				}
			}

		}
		void readVertexes() {
			//读入每个顶点信息
			int n;
			cin >> n; // n个结点

			int indexNo=0;
			for(; indexNo<n; ++indexNo) {
				string label;
				cin>>label;   //TODO: 读入标签到label变量

				//Vertex(int indexNo, const string& label="", int distance=MAX_DIS)
				//TODO: 创建顶点对象v
				Vertex v(indexNo,label);
				this->vertexes.push_back(v);  //把v加入顶点数组
			}

		}
		void readAdjMat() {
			//读取距离矩阵,并存放成员变量adjMat
			int n = this->vertexes.size();

			int i=0;
			for(; i<n; ++i) {
				vector<int> row;  //创建矩阵的一行对象row
				int j=0;
				for(; j<n; ++j) {
					int dis;
					cin>>dis;//TODO: 读取输入的顶点i,j之间的距离,存入变量dis
					row.push_back(dis);//TODO: 将dis插入row
				}
				adjMat.push_back(row);//TODO: 将矩阵的一行row附加到邻接矩阵adjMat中
			}
		}

		void update(int rootNo) {
			//将顶点rootNo选入visited集合之后,
			//更新与rootNo关联的所有结点(未访问):到源点的距离、路径信息
			int i=0;
			int n = vertexes.size();

			Vertex& root = vertexes[rootNo];   //获取rootNo对应顶点对象,便于下面代码写作
			int rootDis = root.distance;

			for(; i < n; ++i) {
				Vertex& v = vertexes[i]; //获取当前顶点对象,便于下面代码写作

				if (v.isVisited)
					continue;//TODO:  如果v已经访问过,则pass

				// TODO: 如果rootNo到i 之间没有边,则pass
				if(adjMat[rootNo][i] == 0)
					continue;

				//计算顶点i:到源点的新距离
				int newDis = rootDis + this->adjMat[rootNo][i];
				if (newDis < v.distance) {
					v.distance = newDis;  //更新顶点i的距离信息
					v.updatePath(vertexes[rootNo].path);	//TODO: 更新顶点i的路径信息, 提示:调用v对象的一个方法
				}
			}
		}

		int select() {
			//从未曾访问的顶点集合中,选择距离源点最短的顶点(其索引号为minNo)
			//返回 minNo
			int minDis = MAX_DIS;
			int minNo = -1;

			int i=0;
			int n = vertexes.size();
			for(; i<n; ++i) {
				Vertex& v = vertexes[i];

				if(v.isVisited)//TODO:如果顶点i已经访问过,则pass
					continue;
				if (v.distance < minDis) {
					//TODO:记录顶点i的距离和编号到minDis、minNo中
					minDis = v.distance;
					minNo = v.indexNo;
				}
			}

			if(minNo == -1)//TODO:检查minNo是否为-1,
				return -1;//若是,则返回-1

			//获得有效的顶点编号
			vertexes[minNo].isVisited = true;
			return minNo;
		}

		void readSourceNo() {
			//从输入读取源结点标签,执行Dijikstra算法

			/
			//1)读取源点
			string slabel;
			cin >> slabel;

			int sourceNo;  //源结点索引
			sourceNo = getNo(slabel);//TODO: 调用一个Graph的成员函数返回标签=slabel的顶点索引号
			//并将编号存入sourceNo

			/
			//2) 初始化源点
			Vertex& source = vertexes[sourceNo];  //获取源点对象source,便于下面代码写作
			source.isVisited = 1;//TODO:设置source的isVisited为true
			source.distance = 0;//TODO:设置source到源点的距离为0
			source.path.push_back(sourceNo);//TODO: 设置source到源点的路径为[sourceNo]

			update(sourceNo);//TODO: 以sourceNo为参数调用update成员函数

			//
			//3)Dikstra主算法
			int i=0;
			int n = vertexes.size();
			for(; i<(n-1); ++i) {

				int v;  //当前未访问过的顶点集合中,距离源点的距离最短的顶点索引号为v

				v = select();//TODO:调用select方法,并将返回值存入v

				if(v == -1)
					break;//TODO: v=-1,则退出for循环

				update(v);//TODO:将v作为参数,调用update方法
			}

			/
			// 4)打印除源点外的其它顶点信息(按顶点索引号顺序打印)
			string sourceLabel = source.label;
			for(i=0; i<n; ++i) {
				if(i == sourceNo) continue;//TODO:如果i=sourceNo,则pass

				Vertex& v = vertexes[i];  //获取当前顶点对象v,便于下述代码写作
				v.displayPath(vertexes,sourceNo);//TODO:调用v的一个方法,打印输出源点到顶点v的距离、路径
			}
		}

		void main() {
			readVertexes();  //读取顶点数组
			readAdjMat();    //读取距离矩阵
			readSourceNo();  //读取源点、并执行Dijkstra算法
		}
};


int main() {

	int t;
	cin >> t;

	while (t--) {
		Graph g;
		g.main();
	}

	return 0;
}
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值