Dijkstra可以在查找最小的d时使用优先队列,这样能降低时间复杂度。
题目描述
多重条件Dijkstra
知识点
图的最短路径,Dijkstra
实现
码前思考
- 只是在裸的Dijkstra算法上增加了
happiness
和average happiness
的比较; - 需要注意的是需要输出最短路径的条数,需要每次都记录下来;
- 第一个路径是不计入
average happiness
的计算的;
代码实现
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
using namespace std;
const int maxn = 210;
const int INF = 0x3fffffff;
struct node{
int v;
int cost;
node(){};
node(int _v,int _cost):v(_v),cost(_cost){}
};
map<string,int> mapp;
map<int,string> rev;
int n;
int k;
int cnt;
//记录终点坐标
int e;
int happy[maxn];
vector<node> adj[maxn];
bool vis[maxn];
int d[maxn];
int h[maxn];
int pre[maxn];
int cntLeast[maxn];
int cntLen[maxn];
void Dijkstra(){
//初始化
fill(vis,vis+maxn,false);
fill(d,d+maxn,INF);
fill(h,h+maxn,0);
fill(cntLeast,cntLeast+maxn,0);
fill(cntLen,cntLen+maxn,0);
d[0]=0;
cntLen[0]=0;
cntLeast[0]=1;
pre[0]=-1;
//开始进行
for(int i=0;i<n;i++){
int u = -1;
int min = INF;
for(int j=0;j<n;j++){
if(vis[j] == false && d[j] < min){
min = d[j];
u = j;
}
}
if(u == e){
return;
}
vis[u] = true;
for(int j=0;j<adj[u].size();j++){
int v = adj[u][j].v;
int cost = adj[u][j].cost;
//如果是有更小的啦
if(vis[v] == false){
if(d[u] + cost < d[v]){
//更新下面数据
cntLeast[v] = cntLeast[u];
h[v] = h[u] + happy[v];
pre[v] = u;
cntLen[v] = cntLen[u]+1;
d[v] = d[u] + cost;
}else if(d[u] + cost == d[v]){
//那么就需要首先增加最短路径的数量
cntLeast[v]+=cntLeast[u];
//然后判断第二个准则
if(h[u] + happy[v] > h[v]){
h[v] = h[u] + happy[v];
pre[v] = u;
cntLen[v] = cntLen[u]+1;
d[v] = d[u] + cost;
}else if(h[u] + happy[v] == h[v]){
//需要判断平均值
double avg1 = h[v]*1.0 / cntLen[v];
double avg2 = h[v]*1.0 / (cntLen[u]+1);
if(avg1 < avg2){
h[v] = h[u] + happy[v];
pre[v] = u;
cntLen[v] = cntLen[u]+1;
d[v] = d[u] + cost;
}
}
}
}
}
}
return;
}
int main(){
fill(happy,happy+maxn,0);
scanf("%d %d",&n,&k);
cnt = 0;
//读取起点
string start;
cin>>start;
mapp[start] = cnt;
rev[cnt] = start;
cnt++;
e = -1;
//接下来输入happy值,注意找ROM
for(int i=0;i<n-1;i++){
char tmp[5];
int val;
scanf("%s %d",tmp,&val);
string city = tmp;
if(city == "ROM"){
e = cnt;
}
happy[cnt] = val;
mapp[city] = cnt;
rev[cnt] = city;
cnt++;
}
//接下来读取邻接距离
for(int i=0;i<k;i++){
string ustr,vstr;
int cost;
cin>>ustr;
cin>>vstr;
cin>>cost;
int u = mapp[ustr];
int v = mapp[vstr];
//printf("%d %d\n",u,v);
adj[u].push_back(node(v,cost));
adj[v].push_back(node(u,cost));
}
//使用Dijkstra算法来解题
Dijkstra();
//输出结果
printf("%d %d %d %d\n",cntLeast[e],d[e],h[e],h[e]/cntLen[e]);
//接下来输出路径,使用栈来保存
stack<int> stk;
int v = e;
while(v!=-1){
stk.push(v);
v = pre[v];
}
while(!stk.empty()){
int u = stk.top();
stk.pop();
string city;
city = rev[u];
cout<<city;
if(city!="ROM"){
cout<<"->";
}
}
return 0;
}
码后反思
- 模板题,主要是思考清楚多重条件的写法!
二刷代码
没有写了,主要使用Dijkstra+DFS会更加清晰!