歷屆試題 大臣的旅費
時間限制:1.0s 內存限制:256.0MB
問題描述
很久以前,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 2 2
1 3 1
2 4 5
2 5 4
樣例輸出1
135
輸出格式
大臣J從城市4到城市5要花費135的路費。
因爲地圖是一棵樹,所以可以知道最終最長的路是以葉子爲起點的,而且樹中點到點的路徑是唯一的。直接DFS超時,不給數據範圍也是醉了。
所以記憶化搜索來剪枝以減少搜索的複雜度。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
const int maxn = 100000;
struct Edge {
int u, v, w;
Edge() {}
Edge(int u, int v, int w) : u(u), v(v), w(w) {}
};
struct Rem {
int nextt, maxx;
Rem() {}
Rem(int nextt, int maxx) : nextt(nextt), maxx(maxx) {}
};
int n, maxx;
vector<int> G[maxn + 5], leaf;
vector<Edge> edges;
bool vis[maxn + 5];
map<int, Rem> m; //int對應當前點,Rem.nextt爲當前點出發最長路路徑中下一點
//Rem.maxx爲從當前點出發的最長路長
int f(int x) {
return x * (x + 1) / 2 + 10 * x;
}
//dfs返回從s出發的最長路長
int dfs(int s) {
int tmax = 0, indexx = 1;
bool flag = false;
for (int i = 0; i < G[s].size(); i++) {
Edge &e = edges[G[s][i]];
int u = e.u, v = e.v, w = e.w;
if (!vis[v]) {
flag = true;
if (m.find(v) != m.end() && m[v].nextt != u) { //由於樹中兩點間路徑是唯一的
if (m[v].maxx + w > tmax) { //所以只要不回頭,一定是路徑下一點
tmax = m[v].maxx + w;
indexx = v;
}
}
else {
vis[v] = true;
int t = dfs(v) + w;
if (tmax < t) {
indexx = v;
tmax = t;
}
vis[v] = false;
}
}
}
if (flag) {
m[s] = Rem(indexx, tmax); //從s出發最長路長爲tmax
return tmax; //且可通過下一步走s->indexx這條邊達到此路長
}
else {
return 0; //搜索到頭,返回0
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n - 1; i++) {
int p, q, d;
scanf("%d%d%d", &p, &q, &d);
edges.push_back(Edge(p, q, d));
G[p].push_back(edges.size() - 1);
edges.push_back(Edge(q, p, d));
G[q].push_back(edges.size() - 1);
}
for (int i = 1; i <= n; i++) {
if (G[i].size() == 1) { //葉子
leaf.push_back(i);
}
}
memset(vis, false, sizeof(vis));
maxx = 0;
m.clear();
for (int i = 0; i < leaf.size(); i++) {
int u = leaf[i];
if (m.find(u) != m.end()) { //之前記憶過了,直接用
maxx = max(maxx, m[u].maxx);
}
else {
vis[u] = true;
maxx = max(maxx, dfs(u));
vis[u] = false;
}
}
printf("%d\n", f(maxx));
return 0;
}