题目
Description
给出N个点,及你的出发点K。
接下来N-1行描述有关边的开始点,结束点,边长。保证图中不会有环
接下来给出数字J,代表你要走多少个点。
接下来J个数字,代表你要走过的点的编号。当然你可以自己选择行进的路线
不一定按给定编号顺序前行,求走过的最短距离。
Format
Input
第一行给出N,K。
2 <= N<= 50000,1<=K<=N
接下来N-1行,每行三个数,进来描述这个地图中的边,边长距离<=1000
接下来给出一个数字J,1<=J <= N-1代表你希望走过的J个点。
最后一行给出J个数字,代表点的编号。1<=编号<=N,且不等于K
Output
如题
Samples
输入数据 1
4 2
1 2 1
4 2 2
2 3 3
2
1 3
输出数据 1
5
输入数据 2
6 1
1 5 10
5 6 20
1 2 5
2 3 7
3 4 1
3
5 2 3
输出数据 2
32
题解
思路
对于这道题,我们已知树、根节点和必须要走过的点,要求走过的最短距离。
可是应该怎么做呢?我们可以先将必须要走过的点标记一下,然后进行dfs,因为模拟时某一条边有可能会重复走,我们就假设每一条边都重复走了。那要减去以K为根节点被标记过的深度的最大值就一定是最优解了(具体过程看注释吧~~)。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node //结构体
{
int ans,len; //ans是与当前结点相连的结点是什么,len是与当前结点相连的结点的边的长度
};
int n,k,deep[50001],num=0;
bool sum[50001];
vector<node> adj[50001]; //定义vector
void dfs(int u,int fa,int dep) //u是当前结点,fa是u的父结点,sum是u与根节点的距离
{
deep[u]=dep; //记录深度
for(int i=0;i<adj[u].size();i++) //枚举与结点u相连的结点
{
node t=adj[u][i];
if(t.ans==fa)continue; //如果相连的结点是它的父结点的话就不做下去了(因为会死循环的,例如2的父结点是1,那么2—>1,又1->2,2->1......)
dfs(t.ans,u,dep+t.len); //dfs
if(sum[t.ans]) //如果它的子节点被标记过的话,记录距离,并将自己赋值成1
{
num=num+2*t.len;
sum[u]=1;
}
}
}
signed main()
{
cin>>n>>k;
for(int i=1;i<n;i++)
{
int c,d,e;
cin>>c>>d>>e;
adj[c].push_back({d,e});
adj[d].push_back({c,e});
}
int q,x;
cin>>q;
for(int i=1;i<=q;i++)
{
cin>>x;
sum[x]=1;
}
dfs(k,0,0);
int um=0;
for(int i=1;i<=n;i++)
{
if(sum[i])
{
um=max(um,deep[i]); //记录以K为根节点被标记过的深度的最大值
}
}
cout<<num-um; //输出
return 0;
}