藍橋杯歷屆試題 大臣的旅費 記憶化搜索DFS

歷屆試題 大臣的旅費  
時間限制: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
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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章