poj 1935 journey 树DP

Journey
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 1425 Accepted: 523

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





#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;


int head[50005];
int next[100005];
int point[100005];
int weight[100005];


struct node
{
int dis; //存储访问该子树但不最终返回根所需长度
int dis_and_return; //存储访问该子树并最终返回根所需长度
bool is_target; //存储该节点是否为目标
bool have_target; //存储该节点为根的子树中是否包含目标
};


node nd[50005];


int n,k;
bool fl[50005];


bool dfs(int v)
{
int ret=0;
fl[v]=1;
nd[v].dis=0x1f1f1f1f; //为找最小,初始化成最大值
nd[v].dis_and_return=0; //初始化成0
for(int e=head[v];e!=-1;e=next[e])
{
if(fl[point[e]])continue;
if(!dfs(point[e]))
{
continue;
}
nd[v].dis_and_return+=(weight[e]*2+nd[point[e]].dis_and_return);
}
if(nd[v].dis_and_return==0) //为0说明所有子树都不包含目标
{
nd[v].dis=0; //将该子树的dis赋为0
if(nd[v].is_target==1) //如果该节点为目标,则返回1,否则返回0
{
return 1;
}
else
{
return 0;
}
}
nd[v].have_target=1; //该子树中有目标点
for(int e=head[v];e!=-1;e=next[e])
{
if(nd[point[e]].have_target==1&&nd[v].dis_and_return-nd[point[e]].dis_and_return-weight[e]+nd[point[e]].dis<nd[v].dis)
{
nd[v].dis=nd[v].dis_and_return-nd[point[e]].dis_and_return-weight[e]+nd[point[e]].dis; //寻找该子树的dis_and_return
}
}
return 1;
}


int main()
{
while(~scanf("%d%d",&n,&k))
{
memset(head,-1,sizeof(head));
memset(next,-1,sizeof(next));
memset(point,-1,sizeof(point));
memset(weight,-1,sizeof(weight));
memset(fl,0,sizeof(fl));
for(int i=1;i<n;i++)
{
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
next[i]=head[a];
point[i]=b;
weight[i]=w;
head[a]=i;


next[i+n]=head[b];
point[i+n]=a;
weight[i+n]=w;
head[b]=i+n;
}
int j;
scanf("%d",&j);
for(int i=1;i<=n;i++)
{
nd[i].have_target=0;
nd[i].is_target=0;
}
for(int i=1;i<=j;i++)
{
int tar;
scanf("%d",&tar);
nd[tar].is_target=1;
nd[tar].have_target=1;
}
dfs(k);
printf("%d\n",nd[k].dis);
}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值