PAT 甲级 1087 All Roads Lead to Rome (DFS+最短路径)(c++版)(附代码注释)(附题意分析)

版权声明:可以转载,请标明作者和来源。原创首发http://kakazai.cn https://blog.csdn.net/yeziand01/article/details/85799527
1087 All Roads Lead to Rome (30 分)

原文链接:http://kakazai.cn/index.php/Kaka/Pat/query/id/177

题目

题目链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805379664297984

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.

Input Specification:

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.

Output Specification:

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 recommanded. 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 recommanded route. Then in the next line, you are supposed to print the route in the format City1->City2->...->ROM.

Sample Input:

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

Sample Output:

3 3 195 97
HZH->PRS->ROM

题意分析

  • 题意

从给定的起点城市到达终点城市ROM,除起点外,每经过一个城市都能收获快乐。从一个城市到达另一个城市也要付出一定代价,比如车费。现在要求找出从起点城市到终点城市代价最小的一条路径,同时该路径能收获最大的快乐(由路径上每个城市所能获得的快乐累加)。如果能收获最大快乐的最短路径还有多条,则选择平均快乐值最大的最短路径。

  • 分析

将城市看成点,城市间代价看成距离,即边的权重,每个城市所能获得的快乐值是点的一个属性。问题变成,求出图中,从给定起点出发到给定终点最短路径。如果最短路径有多条,则取快乐总值最大的那条。若还是有多条路径,则取平均快乐值最大的那条最短路径。

知识点与坑点

  • 知识点

1)DFS,最短路径,用map实现字符串和整数之前的相互转化

  • 坑点

1)平均快乐值是快乐总值除以(路径上总城市数-1),因为并不包括起点城市。

一、DFS

算法思路

1 用深度遍历,求出从起点出发到终点的路径,并挑选出最短的路径

2 深度遍历的同时,要记录快乐值总和,以及路径上的总城市数

3 按要求输出

代码-c++版

#include<iostream>
#include<cstdio>
#include<vector>
#include<map> 
using namespace std;
const int maxn = 200 + 10;
const int INF = 1 << 30;

int happy[maxn],v[maxn];	//城市的快乐值,城市是否被访问过 
int edge[maxn][maxn];	//存储可达城市之间的距离 
vector<int> city[maxn];	//存储某城市的可达周边城市 
map<string, int> id;	//城市字符串转整数编号 
map<int, string> id_string;	//整数编号转城市字符串 
	
vector<int> shortest_p, cur_p;	//最短路径,当前路径 
int shortest_d = INF;	//路径的最短距离
int shortest_c = 0;	//最短路径的数目
int happy_max = 0,av_happy_max = 0; //最短路径中,路径快乐值的最大值,平均快乐值 
int s, d;	//起点,终点 

/*从起点开始深度遍历所有可能到达终点的路径*/    
void dfs(int cur, int cur_happy, int cur_d) {
//cur为当前结点,也是当前路径的终点;
//cur_happy为当前路径的快乐值;cur_d为当前路径的距离 

	/* 当前路径的终点是目标城市*/
    if (cur == d) {
    	
    	//当前路径的总距离更小,则更新所有属性 
        if (cur_d < shortest_d) {	 
            shortest_c = 1;		
            shortest_d = cur_d;
            happy_max = cur_happy;
            av_happy_max = happy_max / (cur_p.size() - 1);//计算平均值时,要去掉起点城市 
            shortest_p = cur_p;
        }
        
        //当前路径的总距离跟现有最短路径的距离相等 
        else if (cur_d == shortest_d) {
            shortest_c++;	//最短路径的数量增加 
            //当前快乐值更大,更新
            if (cur_happy > happy_max) {	 
                happy_max = cur_happy;
                av_happy_max = happy_max / (cur_p.size() - 1);
                shortest_p = cur_p;
            }
            //当前快乐值相同 
            else if (cur_happy == happy_max) {
                int temp = cur_happy / (cur_p.size() - 1);
                //当前平均快乐值更大,则更新 
                if (temp > av_happy_max) {
                    av_happy_max = temp;
                    shortest_p = cur_p;
                }
            }
        }
    }else{
   		/* 从当前城市cur出发,访问其他城市 */
    	for (int i = 0;i < city[cur].size();i++) {
        	int id=city[cur][i];
        	if(v[id]==1||edge[cur][id]==INF)continue;
        	cur_p.push_back(id);	//id入当前路径 
    		v[id] = 1;	//id已被访问
        	dfs(id, cur_happy + happy[id], cur_d + edge[cur][id]);
    	}
    }
    
    /* 从其他城市出发,令当前城市可再度访问*/ 
    v[cur] = 0;
    cur_p.pop_back();
}

/* 按要求输出路径 */ 
void print(vector<int> v) {
    cout << id_string[v[0]];
    for (int i = 1;i<v.size();i++) {
	cout << "->" << id_string[v[i]];
	}
    cout << endl;
}

int main() {
	
	/* 临时变量 */ 
	string s1,s2;
	int in1;
	
	/* 点数,边数,起点城市 */	
	int n,en;	 
    cin >> n >> en >> s1;	
    
    /* 起点城市编号为0 */
	id[s1] = 0;
	id_string[0] = s1;
	s = 0;
	
	/* 其他城市的快乐值以及编号[1,n-1] */
    for (int i = 1;i < n;i++) {
        cin >> s1 >> happy[i];
		id[s1] = i;id_string[i] = s1;
    }
    d = id["ROM"];	//终点城市的编号
    
    /* 存储城市之间的距离和可达城市 */
   	fill(edge[0], edge[0] + maxn * maxn, INF);	//初始化城市之间不可达
    for (int i = 0;i < en;i++) {
        cin >> s1 >> s2 >> in1;
        int city1=id[s1];int city2=id[s2];
        
        edge[city1][city2] = edge[city2][city1] = in1;
        
        city[city1].push_back(city2);
        city[city2].push_back(city1);
    }
    
	/*从起点开始深度遍历所有可能到达终点的路径*/
	cur_p.push_back(s);	//起点进入当前路径 
	v[s] = 1;	//起点已被访问
    dfs(s, 0, 0);	//起点的快乐值为0,路径距离为0 
    
    /*按要求输出*/
    printf("%d %d %d %d\n", shortest_c, shortest_d, happy_max, av_happy_max);
    print(shortest_p);
    
    return 0;
}

代码-python版


猜你喜欢

转载自blog.csdn.net/yeziand01/article/details/85799527