POJ 1935

Journey

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 2060   Accepted: 843

Description

There are n cities in Byteland (numbered from 1 to n), connected by bidirectional roads. The king of Byteland is not very generous, so there are only n-1 roads, but they connect the cities in such a way that it is possible to travel from each city to any other city. 
One day, a traveller Byterider arrived in the city number k. He was planning to make a journey starting in the city k and visiting on his way cities m1 , m2 , ..., mj (not necessarily in this order) --the numbers m i are all different and they are also different from k. Byterider -- like every traveller -- has only a limited amount of money, so he would like to visit all the cities that he has planned to visit using the shortest possible path (starting in the city k). A path is one road or a sequence of roads, where every next road begins in the city where the previous one ends. Help Byterider to determine the length of the shortest path for his journey.

Input

The first line of the standard input contains two integers n and k separated by a single space (2 <= n <= 50000, 1 <= k <= n), n is the number of cities in Byteland and k is the number of the first city on Byterider's path. Each of the following n-1 lines contains the description of one road in Byteland. Line (i + 1) (for 1 <= i <= n-1) contains three integers ai , bi and di separated by single spaces (1 <= ai ; bi <= n, 1 <= di <= 1000), ai and bi are the cities connected by the road, and di is the length of the road. Line (n + 1) contains one integer j -- the number of cities which Byterider would like to visit (1 <= j <= n-1). The next line contains j different integers m i separated by single spaces -- the numbers of the cities that Byterider would like to visit (1 <= mi <= n, mi != k).

Output

The first and only line of the standard output should contain exactly one integer: the length of the shortest path for Byterider's journey.

Sample Input

4 2
1 2 1
4 2 2
2 3 3
2
1 3

Sample Output

5

Source

CEOI 2004 sample task

大致题意:

Byteland有n个城市(编号从1到n),由双向道路连接。 Byteland之王不是很慷慨,所以只有n-1条道路,但它们连接城市的方式可以从每个城市到任何其他城市。
有一天,旅行者Byterider到达了城市号k。 他计划在城市k开始一段旅程,然后前往城市m1,m2,...,mj(不一定按此顺序)访问 - 数字m我都是不同的,它们也与k不同。 Byterider  - 就像每个旅行者 - 只有有限的钱,所以他想访问他计划访问的所有城市,使用最短的路径(从城市k开始)。 路径是一条道路或一系列道路,其中每条下一条道路都在前一条道路的城市开始。 帮助Byterider确定他旅程的最短路径的长度。

标准输入的第一行包含由单个空格分隔的两个整数n和k(2 <= n <= 50000,1 <= k <= n),

n是Byteland中的城市数量,k是数字 Byterider路径上的第一个城市。

以下n-1行中的每一行都包含Byteland中一条道路的描述。

line(i + 1)(对于1 <= i <= n-1)包含由单个空格分隔的三个整数ai,bi和di(1 <= ai; bi <= n,1 <= di <= 1000), ai和bi是道路连接的城市,di是道路的长度。

Line(n + 1)包含一个整数j  -  Byterider想要访问的城市数(1 <= j <= n-1)。

下一行包含j个不同的整数m i由单个空格分隔 -  Byterider想要访问的城市的编号(1 <= mi <= n,mi!= k)。

解题思路:

给你一棵树,要访问树上的m个节点,并且最后不用返回根,所走的最短距离是多少

首先,可以把树上不用走到的地方剪掉,那么叶子节点都是要访问的点

要访问所有叶子节点,那么新的树上的每一条边都是有用的,并且只有一个叶子节点访问完后不用返回

考虑如果最后要返回根,那么就形成了一条欧拉路径,且每条边访问两次。但既然只有一个叶子节点不用返回,那么这个叶子节点必然是最后访问的一个叶子节点,最后要返回根的话,最后一段路径就是这个叶子节点到根的路径,那么我们就只要求出欧拉路径的长度,再剪去一个离根最远的叶子节点的距离,就是答案了

先我们考虑从源点出发到所有自己想要经过的点然后在回到源点sum,显然每条边都必须经过源点(这个我们可以一次dfs求出),但题目的意思是可以不用回到源点,那么我们可以再求源点到所有要经过的点的最远距离ans,于是答案便是sum-ans.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
 
const int maxn = 50005;
struct Edge
{
	int w,v,next;
}edge[maxn<<1];
int n,m,k,pre[maxn],dis[maxn],cnt,sum;
bool vis[maxn];
 
void addedge(int u,int v,int w)
{
	edge[cnt].v = v;
	edge[cnt].w = w;
	edge[cnt].next = pre[u];
	pre[u] = cnt++;
}
 
void dfs(int u,int f)
{
	for(int i = pre[u]; i != -1; i = edge[i].next){
		int v = edge[i].v, w = edge[i].w;
		if(v == f) continue;
		dis[v] = dis[u] + w;
		dfs(v,u);
		if(vis[v]){
			sum += 2*w;
			vis[u] = true;
		}
	}
}
 
int main()
{
	while(scanf("%d%d",&n,&k)!=EOF){
		cnt = 0;
		memset(pre,-1,sizeof(pre));
		memset(vis,false,sizeof(vis));
		for(int i = 1; i < n; i++){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			addedge(u,v,w);
			addedge(v,u,w);
		}
		scanf("%d",&m);
		while(m--){
			int u;
			scanf("%d",&u);
			vis[u] = true;
		}
		sum = 0; dis[k] = 0; m = 0;
		dfs(k,-1);
		for(int i = 1; i <= n; i++){
			if(vis[i] == false) continue;
			m = max(m,dis[i]);
		}
		printf("%d\n",sum - m);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40421671/article/details/88742835