题目链接https://pintia.cn/problem-sets/994805342720868352/problems/994805379664297984
虽然考完了,但闲着没事也做一道。Dijkstra题,除了最短路径外还要满足搜集的快乐点数以及平均快乐点数最高。
一些类:
Route
类的path
成员包含路径的数组(每个城市用id表示,起点id为0),ttl
成员表示该走路径可获得的快乐点数。
class City {
public:
string name;
int hpp;
};
class Route {
public:
vector<int> path;
int ttl;
};
读取数据,给每个城市编号,并将其存入一个mapname2idx
中,通过名字可以获得id
scanf("%d %d", &N, &K);
cty.resize(N);
cin >> cty[0].name;
cty[0].hpp = 0;
name2idx[cty[0].name] = 0;
for (int i = 1; i < N; i++) {
cin >> cty[i].name >> cty[i].hpp;
name2idx[cty[i].name] = i;
}
Dijkstra,输入s
为起点编号。注意在dis[w] == g[v][w] + dis[v]
时,虽然不用更新最短距离,但也要把pre[]
数组赋值好。因为两条路径暂时的cost是相同的,还无法区分优劣。
void Dijkstra(int s) {
dis[s] = 0;
while (1) {
int v = -1;
int min_dis = MAXD;
for (int i = 0; i < N; i++) {
if (!known[i]) {
if (dis[i] < min_dis) {
min_dis = dis[i];
v = i;
}
}
}
if (v < 0)
break;
known[v] = true;
for (int w = 0; w < N; w++) {
if (!known[w]) {
if (g[v][w] < MAXD) {
if (dis[w] > g[v][w] + dis[v]) {
dis[w] = g[v][w] + dis[v];
pre[w].clear();
pre[w].push_back(v);
}
else if (dis[w] == g[v][w] + dis[v])
pre[w].push_back(v);
}
}
}
}
}
根据pre[]
数组来设置路径,实际上就是把所有cost最低的路径都放入rt
数组中,这个递归过程比较容易写错,要特别注意。
当下一个城市的选择有多个时,要给rt[]
拓展空间。
特别注意sz
变量绝不能用rt.size()
替换,因为在用到这个sz
之前,rt.size()
就改变了,所以在它改变前先存下来。
void setRoute(int pos, int now) {
rt[pos].path.push_back(now);
rt[pos].ttl += cty[now].hpp;
if (pre[now].size() > 0) {
for (int j = 0; j < pre[now].size() - 1; j++) {
Route tmp = rt[pos];
rt.push_back(tmp);
}
}
int sz = rt.size();
for (int j = 0; j < pre[now].size(); j++) {
if (j == 0)
setRoute(pos, pre[now][j]);
else
setRoute(sz - j, pre[now][j]);
}
}
因为只需找出最优的一条路径,我们不要排序,仅做一次遍历即可。
Route best_r = rt[0];
for (int i = 1; i < rt.size(); i++) {
if (!cmp(best_r, rt[i])) {
best_r = rt[i];
}
}
最后路径记得反向输出才是从起点到终点的顺序
printf("%d %d %d %d\n", rt.size(), cost, best_r.ttl, best_r.ttl / (best_r.path.size()-1));
for (int i = best_r.path.size()-1; i >= 0; i--) {
if (i != best_r.path.size() - 1)
printf("->");
cout << cty[best_r.path[i]].name;
}
完整代码
#include <iostream>
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<map>
#include<string.h>
#include<string>
using namespace std;
const int MAXD = 99999999;
class City {
public:
string name;
int hpp;
};
class Route {
public:
vector<int> path;
int ttl;
};
int N, K;
map<string, int> name2idx;
int g[201][201];
vector<vector<int>> pre;
bool known[201];
int dis[201];
vector<Route> rt;
vector<City> cty;
void Init() {
rt.resize(1);
rt[0].ttl = 0;
pre.resize(N);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++)
g[i][j] = MAXD;
}
}
void Reset() {
for (int i = 0; i < N; i++) {
dis[i] = MAXD;
known[i] = false;
}
}
void Dijkstra(int s) {
dis[s] = 0;
while (1) {
int v = -1;
int min_dis = MAXD;
for (int i = 0; i < N; i++) {
if (!known[i]) {
if (dis[i] < min_dis) {
min_dis = dis[i];
v = i;
}
}
}
if (v < 0)
break;
known[v] = true;
for (int w = 0; w < N; w++) {
if (!known[w]) {
if (g[v][w] < MAXD) {
if (dis[w] > g[v][w] + dis[v]) {
dis[w] = g[v][w] + dis[v];
pre[w].clear();
pre[w].push_back(v);
}
else if (dis[w] == g[v][w] + dis[v])
pre[w].push_back(v);
}
}
}
}
}
bool cmp(Route x, Route y) {
if (x.ttl != y.ttl)
return x.ttl > y.ttl;
else
return x.path.size() < y.path.size();
}
void setRoute(int pos, int now) {
rt[pos].path.push_back(now);
rt[pos].ttl += cty[now].hpp;
if (pre[now].size() > 0) {
for (int j = 0; j < pre[now].size() - 1; j++) {
Route tmp = rt[pos];
rt.push_back(tmp);
}
}
int sz = rt.size();
for (int j = 0; j < pre[now].size(); j++) {
if (j == 0)
setRoute(pos, pre[now][j]);
else
setRoute(sz - j, pre[now][j]);
}
}
int main() {
scanf("%d %d", &N, &K);
cty.resize(N);
cin >> cty[0].name;
cty[0].hpp = 0;
name2idx[cty[0].name] = 0;
for (int i = 1; i < N; i++) {
cin >> cty[i].name >> cty[i].hpp;
name2idx[cty[i].name] = i;
}
Init();
for (int i = 0; i < K; i++) {
string c1, c2;
int dis;
cin >> c1 >> c2 >> dis;
g[name2idx[c1]][name2idx[c2]] = dis;
g[name2idx[c2]][name2idx[c1]] = dis;
}
Reset();
Dijkstra(0);
int now = name2idx["ROM"];
setRoute(0, now);
Route best_r = rt[0];
for (int i = 1; i < rt.size(); i++) {
if (!cmp(best_r, rt[i])) {
best_r = rt[i];
}
}
int cost = 0;
for (int i = 0; i < best_r.path.size()-1; i++) {
cost += g[best_r.path[i]][best_r.path[i+1]];
}
printf("%d %d %d %d\n", rt.size(), cost, best_r.ttl, best_r.ttl / (best_r.path.size()-1));
for (int i = best_r.path.size()-1; i >= 0; i--) {
if (i != best_r.path.size() - 1)
printf("->");
cout << cty[best_r.path[i]].name;
}
return 0;
}