题目大意:
有N个城市,K条无向边,现在需要从某个给定的起始城市出发,前往名为"ROM"的城市,给出每条边所需要消耗的花费,求从起始城市出发,到达城市ROM所需要的最少花费,并输出最少花费的路径。如果这样的路径有多条,则选择路径上城市的幸福值之和最大的那条路径,如果路径仍然不唯一,则选择路径上城市的平均幸福值最大的那条 。
算法思路:
此题也是典型的Dijkstra算法模板题目,我们这里的最短路径变化为最小花费,不过本质都一样,依然使用dis数组存储每一个点到起点的最短距离,我们通过Dijkstra算法(只衡量第一标尺,也就是只考虑花费最短)获得起点到所有节点的最小花费,以及在此路径上的所有节点的所有前驱结点,然后使用DFS遍历前驱结点数组pre(本质上是一颗树),从终点递归访问每个结点的前驱,当访问到起点的时候,说明获得了一条路径,保存在shortest中,然后计算当前路径上的幸福感之和happ,如果当前happy比全局的最大幸福感max_happiness更大,那么更新 max_happiness = happ;min_num = shortest.size()-1;result = shortest;
(保存路径),如果一样大但是平均幸福感(路径长度)比全局的平均最大幸福感(路径长度)min_num更大,也更新min_num = shortest.size()-1;result = shortest;
并且得累计最短路径条数road_num。由于题目没有给定顶点范围,所以这里采用cityToIndex和intToCity保存顶点和编号(手动赋值)的双向映射以便于遍历和输出。
注意点:
- 1、平均幸福值的计算不包括起点,因为起点的幸福值默认没有,所以是除以当前路径的结点数目-1,仔细观察样例的输出结果就知道了
提交结果:
AC代码:
#include<cstdio>
#include<vector>
#include<string>
#include<iostream>
#include<unordered_map>
#include<algorithm>
using namespace std;
int N,K,start=0,e;// 总人数,边数,起点,终点
int happiness[300];// 点权
int cost[300][300];// 边权
int dis[300];// 每一个城市距离起点的最短距离
bool visited[300];// 访问标记数组
vector<int> pre[300];// 每一个结点的所有前驱
vector<int> shortest;//最短路径
vector<int> result;// 最优路径
unordered_map<string,int> cityToIndex;// 保存城市到编号的映射
unordered_map<int,string> intToCity;// 保存编号到城市的映射
int max_happiness = 0;
int min_num = 0x3fffffff;// 最少结点数目
int road_num = 0;// 最短路径条数
void DFS(int s){
shortest.push_back(s);
if(s==start){
++road_num;
// 到达起点
int c = 0;
int happ = 0;
for(int i=shortest.size()-1;i>=0;--i){
if(i>0){
c += cost[shortest[i]][shortest[i-1]];
}
if(i!=shortest.size()-1){
// 起点没有权值
happ += happiness[shortest[i]];
}
}
if(max_happiness<happ){
max_happiness = happ;
min_num = shortest.size()-1;
result = shortest;
}else if(max_happiness==happ&&min_num>result.size()){
min_num = shortest.size()-1;
result = shortest;
}
shortest.pop_back();
return;
}
for(int i=0;i<pre[s].size();++i){
DFS(pre[s][i]);
}
shortest.pop_back();
}
void Dijkstra(){
// 初始化
fill(dis,dis+300,0x3fffffff);
dis[start] = 0;
// 循环N+1次
for(int i=0;i<N;++i){
// 首先从所有未访问的点中找到距离起点最小的点
int nearest,minDis=0x3fffffff;
for(int j=0;j<N;++j){
if(!visited[j]&&minDis>dis[j]){
nearest = j;
minDis = dis[j];
}
}
if(minDis==0x3fffffff) return ;// 没有找到,说明其他点不再连通
// 优化借助nearest到其他未访问的点的距离
visited[nearest] = true;
for(int j=0;j<N;++j){
if(!visited[j]&&cost[nearest][j]!=0){
if(dis[j]>dis[nearest]+cost[nearest][j]){
dis[j] = dis[nearest]+cost[nearest][j];
pre[j].clear();
pre[j].push_back(nearest);
}else if(dis[j]==dis[nearest]+cost[nearest][j]){
pre[j].push_back(nearest);
}
}
}
}
}
int main(){
string s;
cin>>N>>K>>s;
cityToIndex[s] = start;
intToCity[start] = s;
for(int i=1;i<N;++i){
cin>>s>>happiness[i];
cityToIndex[s] = i;
intToCity[i] = s;
if(s=="ROM") e = i;
}
string a,b;
int C;
for(int i=0;i<K;++i){
cin>>a>>b>>C;
int index_a = cityToIndex[a];
int index_b = cityToIndex[b];
cost[index_a][index_b] = cost[index_b][index_a] = C;
}
Dijkstra();
DFS(e);
printf("%d %d %d %d\n",road_num,dis[e],max_happiness,max_happiness/min_num);
for(int i=result.size()-1;i>=0;--i){
printf("%s",intToCity[result[i]].c_str());
if(i>0) printf("->");
}
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。