大臣的旅费

Posted mabeytang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大臣的旅费相关的知识,希望对你有一定的参考价值。

问题描述

很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

输入格式

输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数

城市从1开始依次编号,1号城市为首都。

接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)

每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。

输出格式

输出一个整数,表示大臣J最多花费的路费是多少。

样例输入1
5
1 2 2
1 3 1
2 4 5
2 5 4
样例输出1
135
输出格式

大臣J从城市4到城市5要花费135的路费。


ALgorithm

一共有 n 个点,共 n - 1 条路线,且任意两点之间有路线,无环,因此这是一个树,也是一个无环无向图。

技术图片

因此就可以使用DFS或BFS进行搜索,或用Floyd算法求多源点之间的最短路(将边的权改为负)。

但是Floyd算法的时间复杂度很高 O(n^3),只能通过75%的数据,事实上,大约超过 300 个点之后都会运行超时,只是它的测试数据较弱罢了

技术图片


 


AC

首先是Floyd算法:

技术图片
 1 /*
 2 * 多源点之间的最短距离 
 3 * 还忽略一个问题, 那就是邻接矩阵的大小 
 4 */
 5 #include<iostream>
 6 #include<cstring>
 7 #include<cmath>
 8 
 9 using namespace std;
10 
11 const int MAX_V = 1009;
12 const int INF = 1e6;
13 
14 int e[MAX_V][MAX_V];
15 int n = 0;
16 
17 void print(int a[MAX_V][MAX_V])
18 {
19     for(int i=1;i<=n;i++){
20         for(int j=1;j<=n;j++){
21             cout<<a[i][j]<<	;
22         }
23         cout<<
;
24     }        
25 }
26 
27 int main()
28 {
29     // Init 放在while(cin)里面出问题,,, 
30     for(int i=1;i<=MAX_V;i++)
31         for(int j=1;j<=MAX_V;j++){
32             if(i == j){
33                 e[i][j] = 0;
34             }
35             else{
36                 e[i][j] = INF;
37             }
38         }
39     while(cin>>n)
40     {    
41         int a, b, t;
42         int ret = 1;
43         for(int i=1;i<n;i++){
44             cin>>a>>b>>t;
45             e[a][b] = e[b][a] = -t;    // 赋负权 
46         }
47         // print(e);
48         // floyd
49         // 居然没有 0 ...... 
50         for(int k=1;k<=n;k++)
51             for(int i=1;i<=n;i++)
52                 for(int j=1;j<=n;j++)
53                     // 非得逼我手算一次才能发现问题所在...(abs) 
54                     if(abs(e[i][j]) > abs(e[i][k] + e[k][j])){
55                         if(e[i][j] == 0)     // 负权要注意一下 ,手算了一次... 
56                             continue;
57                         e[i][j] = e[i][k] + e[k][j];
58                         ret = min(e[i][j], ret);
59                     }    
60         // print(e);
61         ret = -ret;
62         int ans = (11 + (ret+10))*(ret)/2;
63         cout<<ans<<endl;
64         break;
65     }
66 
67     return 0;
68 }
View Code

 接下来是深搜:

技术图片
  1 /*
  2 * 比较典型的图或树的搜索
  3 * 这个图比较稀疏, 邻接表可能会好一点 
  4 * 我们只要搜索度为 1 的点就好, 它一定是起点或者终点
  5 * 因为如果度大于 1 的点是终点的话,一定可以继续走下去 
  6 - 后记 - :我没想到怎样避免不搜索图中遇到它... 
  7 - 现在有想法了, 如果它是起点,那么 dis = 0 
  8 * 那么它一定还可以继续前进 
  9 * -----------------------------------
 10 * 此外, 还可以用Floyd算法来求多源点之间的最短距离
 11 * 这里的距离是求最长距离,所以赋予其负的权值就 ok 
 12 */
 13 #include<iostream>
 14 #include<vector>
 15 #include<algorithm>
 16 #include<cstring>
 17 
 18 using namespace std;
 19 
 20 const int MAX_V = 10009; // 题目没有说最大城市的数量 
 21 int ret = -1;             // 最大花费 
 22 int dis = 0;             // 当前走的距离 
 23 bool book[MAX_V];
 24 int s = 0;
 25 int km = 0;
 26 int loc = 0;
 27 
 28 struct edge{
 29     int to;        // 去的点 
 30     int len;    // 两点之间的距离 
 31 };
 32 
 33 vector<edge> G[MAX_V];
 34 
 35 // 搜索起点,从 1 开始找最远的距离 
 36 void finds(int a, int km)
 37 {
 38     // cout<<a<<endl;
 39     if(G[a].size() == 1 && km != 0){
 40         if(km > s){
 41             loc = a;
 42             s = km;
 43         }
 44     }
 45     for(int i=0;i<G[a].size();i++){
 46         if(book[G[a].at(i).to] == true){
 47             book[G[a].at(i).to] = false; // 标记当前点 
 48             finds(G[a].at(i).to, km+G[a].at(i).len);
 49             book[G[a].at(i).to] = true;
 50         }
 51     }
 52 }
 53 
 54 // 费用最大,即走的路程最多 
 55 void dfs(int a, int dis)
 56 {    
 57     if(G[a].size() == 1 && dis != 0){ // 到了度为1的点,搜索结束 
 58         ret = max(dis, ret);
 59         return;
 60     } 
 61     for(int i=0;i<G[a].size();i++){
 62         if(book[G[a].at(i).to] == true){
 63             book[G[a].at(i).to] = false; // 标记当前点 
 64             dfs(G[a].at(i).to, dis+G[a].at(i).len);
 65             book[G[a].at(i).to] = true;
 66         }
 67     }
 68     
 69     return;
 70 }
 71 
 72 int main()
 73 {
 74     int n;
 75     // while(cin>>n)
 76     cin>>n;
 77     {
 78         int go;
 79         edge E1, E2;
 80         while(--n)
 81         {
 82             cin>>go>>E1.to>>E1.len;
 83             G[go].push_back(E1);
 84             E2.to = go; E2.len = E1.len; 
 85             G[E1.to].push_back(E2);
 86         }
 87         memset(book, true, sizeof(book));
 88         book[1] = false;
 89         finds(1, 0);
 90         //cout<<"loc: "<<loc<<endl;
 91         //cout<<"s: "<<s<<endl;
 92         memset(book, true, sizeof(book));
 93         book[loc] = false;
 94         dfs(loc, 0);
 95         //cout<<"ret: "<<ret<<endl;
 96         cout<<((11 + (ret+10))*(ret)/2)<<endl;
 97     }
 98     
 99     return 0;
100 }
101 /* 好像是错误的,通过的数据应该是巧合 
102 edge mx;
103 mx.len = 0;
104 int s = 0;
105 for(int i=1;i<=N;i++){ // 会不会一定经过权值最大的度为1的点? 
106             if(G[i].size() == 1){
107                 if(G[i][0].len > mx.len){
108                     mx = G[i][0];
109                     s = i;
110                 }
111             }
112         }
113 */
View Code

 深搜分两次,第一次找起点,第二次找最长路径。就像提示里说的那样......

技术图片

2019-02-18

21:19:25





以上是关于大臣的旅费的主要内容,如果未能解决你的问题,请参考以下文章

大臣的旅费---树的直径(dfs)

大臣的旅费树型dp + 求树最长链

算法笔记_191:历届试题 大臣的旅费(Java)

蓝桥杯 大臣的旅费_树的最长度_两次DFS

双指针,BFS和图论

蓝桥日记⑥2013第四届省赛(软件类)JavaA组@答案解析