AOJ0189 Convenient Location

一、题目大意

有N条双向边将城市里的小镇连通起来,寻找出到达其他所有小镇距离之和最短的小镇,并输出该距离之和。

二、解题思路

用Set记录有哪些小镇,用Vector记录每个小镇与其他小镇之间相连的边,遍历Set,用Dijkstra算法求解每个小镇到其他小镇的距离之和。然后取最小的就可以。

三、代码

#include <iostream>
#include <queue>
#include <vector>
#include <set>
using namespace std;
//用来求出最短路径的结构体
struct Node {
	//节点编号
	int nodeId;
	//起点到达该节点的最短距离
	int theShortestDistanceToTheNode;
	//重载 < 运算符
	bool operator<(const Node& node) const {
		return this->theShortestDistanceToTheNode<node.theShortestDistanceToTheNode;
	}
	//构造方法
	Node(int _nodeId,int _theShortestDistanceToTheNode):nodeId(_nodeId),theShortestDistanceToTheNode(_theShortestDistanceToTheNode) {}
};
//定义比较器
struct NodeComparator {
	//比价器中为左边大于右边,则优先队列会将数值小的放在对首
	bool operator()(const Node& nodeLeft,const Node& nodeRight) {
		return nodeLeft.theShortestDistanceToTheNode>nodeRight.theShortestDistanceToTheNode;
	}
};
//顶点的一条边
struct edge {
	//边的端点的节点编号
	int endPointNodeId;
	//变的长度
	int length;
	edge(int _endPointNodeId,int _length):endPointNodeId(_endPointNodeId),length(_length) {}
};
//最多的节点个数
const int MAX_NODE_COUNT=16;
//节点个数
int nodeCount;
//边的个数
int edgeCount;
//每一个点都有一个vector,存放它所能够到达的边
vector<edge> edgeOfNodeId[MAX_NODE_COUNT];
//代表存放图中节点的队列
set<int> nodeIdSet;
//到达某个节点的最小距离
int distanceToNodeId[MAX_NODE_COUNT];
//无穷大
const int inf=0x3f3f3f3f;
//迪杰斯特拉算法
void dijkstra(int startNodeId) {
	priority_queue<Node,vector<Node>,NodeComparator > priorityQueue;
	//初始化距离都为无穷大
	for(int i=0; i<MAX_NODE_COUNT; i++) {
		distanceToNodeId[i]=inf;
	}
	//起点到本身的距离为0
	distanceToNodeId[startNodeId]=0;
	//将起点放入优先队列
	priorityQueue.push(Node(startNodeId,0));
	while(!priorityQueue.empty()) {
		//当前最短距离已经确定的点
		Node currentNode=priorityQueue.top();
		//出队
		priorityQueue.pop();
		//如果起点到达该点的距离已经被再次更新过,则执行下一次循环
		if(distanceToNodeId[currentNode.nodeId]<currentNode.theShortestDistanceToTheNode) {
			continue;
		}
		//遍历当前节点的所有边
		for(int edgeId=0; edgeId<edgeOfNodeId[currentNode.nodeId].size(); edgeId++) {
			//取出一条边
			edge currentEdge=edgeOfNodeId[currentNode.nodeId][edgeId];
			//如果, 距离(起点->当前边终点) >  距离(起点->跳板节点->当前边终点)  那么进入if
			if(distanceToNodeId[currentEdge.endPointNodeId]>distanceToNodeId[currentNode.nodeId]+currentEdge.length) {
				//更新起点到当前边终点的距离
				distanceToNodeId[currentEdge.endPointNodeId]=distanceToNodeId[currentNode.nodeId]+currentEdge.length;
				//该点的最短路径已经确定,放入队列中。再去作为跳板节点更新其他的距离
				priorityQueue.push(Node(currentEdge.endPointNodeId,distanceToNodeId[currentEdge.endPointNodeId]));
			}
		}
	}
}
void getEdgeCountAndNodeCount() {
	scanf("%d",&edgeCount);
	nodeCount=edgeCount;
}
void getInputGraphData() {
	//起始节点
	int startNodeId;
	//终止节点
	int endNodeId;
	//边的长度
	int lengthOfEdge;
	for(int i=0; i<edgeCount; i++) {
		//依次输入两个端点和边的长度
		scanf("%d%d%d",&startNodeId,&endNodeId,&lengthOfEdge);
		//左端点添加这条边
		edgeOfNodeId[startNodeId].push_back(edge(endNodeId,lengthOfEdge));
		//右端点添加这条边
		edgeOfNodeId[endNodeId].push_back(edge(startNodeId,lengthOfEdge));
		//将节点编号放入集合,方便以后去重遍历
		nodeIdSet.insert(startNodeId);
		nodeIdSet.insert(endNodeId);
	}
}
//初始化数据结构
void initEdgeArray() {
	//将所有节点的边的清掉
	for(int i=0; i<MAX_NODE_COUNT; i++) {
		edgeOfNodeId[i].clear();
	}
	//清空节点集合
	nodeIdSet.clear();
}
//计算节点到其他节点的距离之和
int calculateSumOfDistance() {
	int sumOfDistance=0;
	set<int>::iterator ite;
	for(ite=nodeIdSet.begin(); ite!=nodeIdSet.end(); ite++) {
		int nodeId=*ite;
		sumOfDistance+=distanceToNodeId[nodeId];
	}
	return sumOfDistance;
}
int main() {
	while(true) {
		//输入节点数量
		getEdgeCountAndNodeCount();
		//如果输入为0则程序结束
		if(edgeCount==0&&nodeCount==0) {
			break;
		}
		//初始化数据结构
		initEdgeArray();
		//输入图的信息
		getInputGraphData();
		//定义初始化最佳节点
		int currentMinDistanceNodeId=0;
		//最佳节点到其他节点的距离和
		int currentMinDistance=inf;
		//遍历Set
		set<int>::iterator ite;
		for(ite=nodeIdSet.begin(); ite!=nodeIdSet.end(); ite++) {
			//取到一个节点ID
			int nodeId=*ite;
			//调用迪杰斯特拉算法
			dijkstra(nodeId);
			//求出距离之和
			int sumOfThisNode=calculateSumOfDistance();
			//如果距离之和小于当前的最小距离,记录节点信息和最小距离
			if(sumOfThisNode<currentMinDistance) {
				//最小距离
				currentMinDistance=sumOfThisNode;
				//节点ID
				currentMinDistanceNodeId=nodeId;
			}
		}
		//输入最佳节点Id和最小的距离
		printf("%d %d\n",currentMinDistanceNodeId,currentMinDistance);
	}
	return 0;
}

四、总结

掌握更多的数据结构,能够更好的解题,也有助于平时的开发工作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值