POJ 1935 Journey

給你一棵樹,要訪問樹上的m個節點,並且最後不用返回根,所走的最短距離是多少

首先,可以把樹上不用走到的地方剪掉,那麼葉子節點都是要訪問的點

要訪問所有葉子節點,那麼新的樹上的每一條邊都是有用的,並且只有一個葉子節點訪問完後不用返回

考慮如果最後要返回根,那麼就形成了一條歐拉路徑,且每條邊訪問兩次,既然只有一個葉子節點不用返回,那麼這個葉子節點必然是最後訪問的一個葉子節點,最後要返回根的話,最後一段路徑就是這個葉子節點到根的路徑,那麼我們就只要求出歐拉路徑的長度,再剪去一個離根最遠的葉子節點的距離,就是答案了

思路很巧妙,我原來想的是找第一個分叉點,但忽略了分叉點下面可能還有分叉點,中間的處理是不同的


代碼:

#include<iostream>
#include<memory.h>
#include<string>
#include<cstdio>
#include<algorithm>
#include<math.h>
#include<stack>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int MAX=50005;
struct node 
{
	int v,w,next;
}g[MAX*5];
int adj[MAX],dis[MAX],dp[MAX],e,n,m;
int flag[MAX],wanted[MAX];
void add(int u,int v,int w)
{
	g[e].v=v; g[e].w=w; g[e].next=adj[u]; adj[u]=e++;
}
int pre_dfs(int u,int fa)
{
	int i,v;
	int cnt=wanted[u];
	for(i=adj[u];i!=-1;i=g[i].next)
	{
		v=g[i].v;
		if(v==fa)
			continue;
		cnt+=pre_dfs(v,u);
	}
	flag[u]=cnt;
	return cnt>0;
}
void dfs(int u,int fa,int d)
{
	int i,v,tmp=0;
	dis[u]=d;
	dp[u]=0;
	for(i=adj[u];i!=-1;i=g[i].next)
	{
		v=g[i].v;
		if(v==fa||!flag[v])
			continue;
		dfs(v,u,d+g[i].w);
		dp[u]+=dp[v]+g[i].w*2;
	}
}
int main()
{
	int i,j,k,l,root;
	while(scanf("%d%d",&n,&root)!=EOF)
	{
		memset(adj,-1,sizeof(adj));
		memset(flag,0,sizeof(flag));
		memset(wanted,0,sizeof(wanted));
		e=0;
		for(l=1;l<n;l++)
		{
			scanf("%d%d%d",&i,&j,&k);
			add(i,j,k);
			add(j,i,k);
		}
		scanf("%d",&m);
		while(m--)
		{
			scanf("%d",&i);
			wanted[i]=1;
		}
		pre_dfs(root,-1);
		int maxx=-1;
		dfs(root,-1,0);
		for(i=1;i<=n;i++)
		{
			if(flag[i])
				maxx=max(maxx,dis[i]);
		}
		printf("%d\n",dp[root]-maxx);
	}
	return 0;
}




發佈了242 篇原創文章 · 獲贊 5 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章