Vlad and Unfinished Business
题意:
给一棵含有n个结点的树,起点s,终点e,还有其他k个标记点。
问从s出发遍历所以标记点最后到达e点的最短路径。
思路:
先找到从s到e的路径,然后遍历路径上的所有点,找到从该点出发能到标记点并返回的最短路径。
f[i]表示从i点出发遍历能够到达的标记点并返回的最短路径。
具体看代码
代码:
/*************************************************************************
> File Name: d.cpp
> Author: Beans
> Mail: 3112748286@qq.com
> Created Time: 2023/5/12 18:02:07
************************************************************************/
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <map>
#include <unordered_map>
#define int long long
#define endl '\n'
using namespace std;
const int maxn = 3e5 + 7;
int t, n, k;
int s, e;
void getp(int u, int fa, bool& ok, vector<vector<int>>& g, vector<int>& p, map<int, int>& inp){
if(u == e){
ok = true;
}
for(auto i : g[u]){
if(i == fa || ok) continue;
getp(i, u, ok, g, p, inp);
}
if(ok){
p.push_back(u);
inp[u] = 1;
}
}
void dfs(int u, int fa, vector<int>& f, vector<vector<int>>& g, map<int, int>& inp, map<int, int>& nd){
for(auto i : g[u]){
if(i == fa || inp[i]) continue;
dfs(i, u, f, g, inp, nd);
if(nd[i] || f[i])
f[u] += f[i] + 2;
}
}
void solve(){
cin >> n >> k;
cin >> s >> e;
map<int, int> nd;
int x;
for(int i = 1; i <= k; i ++ ){
cin >> x;
nd[x] = 1;
}
vector<vector<int>> g(n + 1, vector<int>());
for(int i = 1; i <= n - 1; i ++ ){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> p;
map<int, int> inp;
bool ok = false;
int ans = 0;
getp(s, 0, ok, g, p, inp);
vector<int> f(n + 1, 0);
for(auto i : p){
dfs(i, 0, f, g, inp, nd);
ans += f[i];
}
cout << ans + p.size() - 1 << endl;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> t;
while(t -- )
solve();
}