题目地址
牛客网的PAT练习(https://www.nowcoder.com/pat/5/problem/4315):1002 All Roads Lead to Rome
题目描述
Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.
输入描述:
Each input file contains one test case. For each case, the first line contains 2 positive integers N (2<=N<=200), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N-1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format "City1 City2 Cost". Here the name of a city is a string of 3 capital English letters, and the destination is always ROM which represents Rome.
输出描述:
For each test case, we are supposed to find the route with the least cost. If such a route is not unique, the one with the maximum happiness will be recommended. If such a route is still not unique, then we output the one with the maximum average happiness -- it is guaranteed by the judge that such a solution exists and is unique. Hence in the first line of output, you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommended route. Then in the next line, you are supposed to print the route in the format "City1->City2->...->ROM".
输入例子:
6 7 HZH ROM 100 PKN 40 GDN 55 PRS 95 BLN 80 ROM GDN 1 BLN ROM 1 HZH PKN 1 PRS ROM 2 BLN HZH 2 PKN GDN 1 HZH PRS 1
输出例子:
3 3 195 97 HZH->PRS->ROM
思路
其实还是路径规划的问题,使用dijkstra算法。算法步骤为:
a、将所有的点分为U,V两个集合,U表示已经规划好了路径,V表示为规划路径,初始时,将起点v加入集合U,其他点加入集合V;
b、从V中选取到起点v最近的k,将点k加入到U中;
c、更新将V中与k相邻的所有点到起点v的距离(假设i为V中与k相邻的一个点,若i到k的距离+k到v的距离 < i到v的距离,则更新i到v的距离,并设i的父节点为k);
d、重复bc步骤,知道所有点加入了U中。
在本题中,主要的变化是在步骤c中,不仅需要考虑路径的距离,还需要考虑经过路径累计的happiness,城市数量等。
答案
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <queue>
using namespace std;
#define N 201
int MAX = 999999;
string str_start, str_dest = "ROM";
int i_start, i_dest;
int n, k;
int costs[N][N] = { 0/*MAX*/ };
map<string, int> city2id;
vector<string> names;
int citysHapiness[N] = { 0 };
int f[N] = { -1 };
bool visited[N] = {false};
int cost[N] = { MAX };
int depth[N] = { 0 };
int totalHapiness[N] = { 0 };
int pathnum[N] = { 0 };
vector<vector<int>> paths;
void setFather(int child, int father)
{
f[child] = father;
//visited[i]
cost[child] = cost[father] + costs[child][father];
depth[child] = depth[father] + 1;
totalHapiness[child] = citysHapiness[child] + totalHapiness[father];
//pathnum[child] = pathnum[father];
//这句话是错误的,
//只有在通过新的父节点使cost变小的时候才适用,
//但是在cost相同(新的父节点使hapiness变大或经过城市变小)的情况下,这句话逻辑是错误的
}
void dij(int start)
{
f[start] = -1;
for (int i = 0; i < n; i++)
{
int tmp = costs[start][i];
if (tmp != 0)
f[i] = start;
}
// 起点
f[start] = -1;
/* visited[start] = true;*/
cost[start] = 0;
depth[start] = 0;
totalHapiness[start] = 0;
pathnum[start] = 1;
for (int i = 0; i < n; i++)
{
// 找到未访问点中,距离起点最近的
int k, minDist = MAX + 1;
for (int j = 0; j < n; j++)
{
if (!visited[j] && cost[j] < minDist)
{
k = j;
minDist = cost[j];
}
}
// 处理该点及相连的点
visited[k] = true;
for (int i = 0; i < n; i++)
{
if (!visited[i] && (costs[i][k]!=0))
{
if (cost[i] > minDist + costs[k][i])
{
setFather(i, k);
pathnum[i] = pathnum[k];
}
else if (cost[i] == minDist + costs[k][i])
{
pathnum[i] += pathnum[k];
if (totalHapiness[i] < totalHapiness[k] + citysHapiness[i])
{
setFather(i, k);
}
else if (totalHapiness[i] == totalHapiness[k] + citysHapiness[i])
{
if (depth[i] > depth[k] + 1)
{
setFather(i, k);
}
}
}
}
}
}
}
int main()
{
for (int i = 0; i < N; i++)
{
f[i] = -1;
visited[i] = false;
cost[i] = MAX;
}
cin >> n >> k >> str_start;
// start point
i_start = 0;
city2id[str_start] = 0;
names.push_back(str_start);
// read city's hapiness
string tmp_str;
int tmp_int;
for (int index = 1; index < n; index++)
{
cin >> tmp_str >> tmp_int;
city2id[tmp_str] = index;
citysHapiness[index] = tmp_int;
names.push_back(tmp_str);
}
i_dest = city2id[str_dest];
// read cost
string tmp1, tmp2;
int tmp_i_1, tmp_i_2;
for (int index = 0; index < k; index++)
{
cin >> tmp1 >> tmp2 >> tmp_int;
tmp_i_1 = city2id[tmp1];
tmp_i_2 = city2id[tmp2];
costs[tmp_i_1][tmp_i_2] = costs[tmp_i_2][tmp_i_1] = tmp_int;
}
//
dij(i_start);
// output
int tmp_i_dest = i_dest;
vector<string> ppp;
while (f[tmp_i_dest] != -1)
{
ppp.push_back(names[tmp_i_dest]);
tmp_i_dest = f[tmp_i_dest];
}
ppp.push_back(names[tmp_i_dest]);
cout << pathnum[i_dest] << " " << cost[i_dest] << " " << totalHapiness[i_dest] << " "
<< totalHapiness[i_dest] / depth[i_dest] << endl;
for (int i = ppp.size() - 1; i > 0; i--)
{
cout << ppp.at(i) << "->";
}
cout << ppp.at(0);
return 0;
}