解题思路: 先我们考虑从源点出发到所有自己想要经过的点然后在回到源点sum,显然每条边都必须经过源点(这个我们可以一次dfs求出),但题目的意思是可以不用回到源点,那么我们可以再求源点到所有要经过的点的最远距离ans,于是答案便是sum-ans.
这道题的思路确实是很巧妙,一开始我还是在想如何表示从某一点回来的状态,数据太大用状态压缩肯定不行,结果就没思路了,看了别人的思路确实是抓住了这道题的精髓。。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 50005; struct Edge { int w,v,next; }edge[maxn<<1]; int n,m,k,pre[maxn],dis[maxn],cnt,sum; bool vis[maxn]; void addedge(int u,int v,int w) { edge[cnt].v = v; edge[cnt].w = w; edge[cnt].next = pre[u]; pre[u] = cnt++; } void dfs(int u,int f) { for(int i = pre[u]; i != -1; i = edge[i].next){ int v = edge[i].v, w = edge[i].w; if(v == f) continue; dis[v] = dis[u] + w; dfs(v,u); if(vis[v]){ sum += 2*w; vis[u] = true; } } } int main() { while(scanf("%d%d",&n,&k)!=EOF){ cnt = 0; memset(pre,-1,sizeof(pre)); memset(vis,false,sizeof(vis)); for(int i = 1; i < n; i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } scanf("%d",&m); while(m--){ int u; scanf("%d",&u); vis[u] = true; } sum = 0; dis[k] = 0; m = 0; dfs(k,-1); for(int i = 1; i <= n; i++){ if(vis[i] == false) continue; m = max(m,dis[i]); } printf("%d\n",sum - m); } return 0; }