题意:一个人在m城镇,想参观这座城的k的城镇,求走过的最短路。题目链接
题解:假设从m点出发,最后回到m点,则 len为所有点的权值和乘以2,如果不会到m点,应该停留在叶子节点,这个以节点一定离m最远的点,在这条最远的路上,只会走一遍。所以最后结果应为 len 减去离m最远的距离。
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
#define FF freopen("Input.txt","r",stdin)
#define mem(x,y) memset(x,y,sizeof(x))
#define ll long long
#define inf 1000020
const int N=50010;
struct Graph
{
int head[N*2],val[N*2],pnt[N*2],next[N*2],tot;
void init()
{
tot=0;
mem(head,-1);
}
void add(int u,int v,int w)
{
pnt[tot]=v;
val[tot]=w;
next[tot]=head[u];
head[u]=tot++;
}
}G;
int tot,dis[N],vis[N],have[N],len;
void dfs1(int u) //标记去想要参观的城市需要走的点。
{
vis[u]=1;
for(int i=G.head[u];i!=-1;i=G.next[i])
{
int v=G.pnt[i];
if(vis[v]) continue;
dfs1(v);
have[u]+=have[v];
}
}
void dfs2(int u)
{
vis[u]=1;
for(int i=G.head[u];i!=-1;i=G.next[i])
{
int v=G.pnt[i];
int w=G.val[i];
if(vis[v] || have[v]==0) continue;
len+=w; //len为所有边的和
dfs2(v);
if(dis[u]<dis[v]+w) dis[u]=dis[v]+w;//距离m最远的距离。
}
}
int main()
{
//FF;
int n,i,m;
while(~scanf("%d%d",&n,&m))
{
G.init();mem(have,0);
int k;
for(i=1;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
G.add(a,b,c); G.add(b,a,c);
}
scanf("%d",&k);
while(k--)
{
scanf("%d",&i);
have[i]=1;
}
mem(vis,0);
dfs1(m);
mem(vis,0);
mem(dis,0);
dfs2(m);
printf("%d\n",len*2-dis[m]);
}
return 0;
}
解法二:dp 1不回到 父节点几点,dp2回到。
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
#define FF freopen("Input.txt","r",stdin)
#define mem(x,y) memset(x,y,sizeof(x))
#define ll long long
#define inf 1000020
const int N=50010;
int dp1[N],dp2[N];
struct Graph
{
int head[N*2],val[N*2],pnt[N*2],next[N*2],tot;
void init()
{
tot=0;
mem(head,-1);
}
void add(int u,int v,int w)
{
pnt[tot]=v;
val[tot]=w;
next[tot]=head[u];
head[u]=tot++;
}
}G;
int tot,dis[N],vis[N],have[N],len;
void dfs1(int u)
{
vis[u]=1;
for(int i=G.head[u];i!=-1;i=G.next[i])
{
int v=G.pnt[i];
if(vis[v]) continue;
dfs1(v);
have[u]+=have[v];
}
}
void dfs2(int s)
{
vis[s]=1;
for(int i=G.head[s];i!=-1;i=G.next[i])
{
int t=G.pnt[i];
int w=G.val[i];
if(vis[t] || have[t]==0) continue;
dfs2(t);
dp1[s]=min(dp2[s]+dp1[t]+w,dp1[s]+dp2[t]+2*w);
// 从s到t,不回到s,到s的t子树中,到s的其他子树中。
dp2[s]+=dp2[t]+2*w;//s访问t的回到s。
}
}
int main()
{
//FF;
int n,i,m;
while(~scanf("%d%d",&n,&m))
{
G.init();mem(have,0);
int k;
for(i=1;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
G.add(a,b,c); G.add(b,a,c);
}
scanf("%d",&k);
while(k--)
{
scanf("%d",&i);
have[i]=1;
}
mem(vis,0);
dfs1(m);
mem(vis,0); mem(dp1,0);mem(dp2,0);
dfs2(m);
printf("%d\n",dp1[m]);
}
return 0;
}