题目
Description
给出一棵树N个点及数字K
接下来N-1行描述有关边的开始点,结束点.
保证图中不会有环
接下来K个数字,代表你要走过的点的编号.当然你可以自己选择出发点及行进的路线
不一定按给定编号顺序前行,求走过的最短距离。
Format
Input
第一行给出N,K。
2 <= N<= 50000,1<=K<=N
接下来N-1行,描述这个树
最后一行给出K个数字,代表点的编号。1<=编号<=N
Output
如题
Samples
输入数据 1
4 2
1 2
4 2
2 3
1 3
输出数据 1
2
输入数据 2
11 3
1 2
1 3
3 4
4 5
5 11
3 6
6 7
7 8
8 9
9 10
2 10 11
输出数据 2
12
Hint
注意当K=1的情况
题解
其实这一题跟Journey这道题很像,只是改变了k的值且没有了边权而已。
我们首先的思路是暴力枚举K个数字,可是这样的话只有48分!!!!!!!😭😭😭
那要怎么编呢?我们先来分析一下样例的路线:
![](https://img-blog.csdnimg.cn/img_convert/73881cf8f8333e69105e0984bcc72ac0.png)
画红色的线是路径。
我们先观察一下:这一组样例的起始点是深度最深且是必须要走过的点!
发现了什么?我们现在有一个大胆的猜测:我们是不是要从深度最深且是必须要走过的那个点开始遍历呢???
YES!因为这样做大大减少了往返的距离,使得便利到该节点时又返回到根结点(因为该结点深度最深,不能再往下便利了,如果还有结点,那也不是必须要走过的那个点)的距离为0(因为该结点就是根节点)。
于是我打了一个代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,dep[50001],num=0;
bool sum[50001];
vector<int> adj[50001];
void dfs(int u,int fa,int d)
{
dep[u]=d;
for(int i=0;i<adj[u].size();i++)
{
int t=adj[u][i];
if(t==fa)continue;
dfs(t,u,d+1);
if(sum[t])
{
sum[u]=1;
num=num+2;
}
}
}
void dfs1(int u,int fa,int d)
{
dep[u]=d;
for(int i=0;i<adj[u].size();i++)
{
int t=adj[u][i];
if(t==fa)continue;
dfs1(t,u,d+1);
}
}
signed main()
{
cin>>n>>k;
for(int i=1;i<n;i++)
{
int c,d;
cin>>c>>d;
adj[c].push_back(d);
adj[d].push_back(c);
}
dfs1(1,0,0);
int x[50001],y=0,pop=0;
for(int i=1;i<=k;i++)
{
cin>>x[i];
if(y<dep[x[i]])
{
y=dep[x[i]];
pop=x[i];
}
sum[x[i]]=1;
}
if(k==1)
{
cout<<0;
return 0;
}
num=0;
memset(dep,0,sizeof(dep));
dfs(pop,0,0);
int um=0;
for(int i=1;i<=n;i++)
{
if(sum[i])
{
um=max(um,dep[i]);
}
}
cout<<num-um;
return 0;
}
结果...........
![](https://img-blog.csdnimg.cn/img_convert/0dde69356b46b138ceb5058c53ac596d.png)
WHAT? ? ? ?
![](https://img-blog.csdnimg.cn/img_convert/08d47ac46592d2b98cc9dc4b9a6fa103.webp?x-oss-process=image/format,png)
我发现有Runtime Error,于是我把数组开大到10^6后就
AC了!!!!!!
![](https://img-blog.csdnimg.cn/img_convert/b4c9a57fdeb63895dad5fb0998a3e786.png)