[POJ 1935] Journey

Posted newera

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POJ 1935] Journey相关的知识,希望对你有一定的参考价值。

Link:

POJ1935 传送门

Solution:

一道吓唬人的水题

 

注意这是一棵树,两点间仅有唯一的路径

于是每个“关键点”和起点只有一条路径,想去起点另一棵子树上的节点必须要回到起点

 

如果必须要回到起点,答案$res$就是除去无用边后整棵树总距离$*2$,

因为不必回到起点,最终结果为$res-mx$,$mx$为距起点的最远点的距离

 

除去无用边的方式:给每个“关键点”打上$vis$标记,这样最远点之后的点就不会被$dfs$到了

Code:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <utility>
#include <vector>

using namespace std;
typedef pair<int,int> P;
#define X first
#define Y second
const int MAXN=5e4+10;
vector<P> G[MAXN];
int n,k,root,dist[MAXN],vis[MAXN],mx,res,x,y,z;

void dfs(int u,int anc)
{
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i].X;
        if(v==anc) continue;
        dist[v]=dist[u]+G[u][i].Y;
        dfs(v,u);
        if(vis[v]) vis[u]=true,res+=G[u][i].Y*2; //传递标记
    }
}

int main()
{
    scanf("%d%d",&n,&root);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        G[x].push_back(P(y,z));G[y].push_back(P(x,z));
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
        scanf("%d",&x),vis[x]=true; //打上标记
    dfs(root,0);
    for(int i=1;i<=n;i++)
        if(vis[i]) mx=max(mx,dist[i]);
    printf("%d",res-mx);
    return 0;
}

Review:

(1)对“树”这个条件中“两点之间只有一条路径”这个性质不够敏感,

因此未能看出到达一棵子树的最远点后必须要回到起点再出发这一推论

 

(2)除去无用边的方法很妙:设置$vis=true$,将更远的点截去

同时传递$vis$的值来更新答案

 

以上是关于[POJ 1935] Journey的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2488 A Knight's Journey-dfs

Poj机试 A Knight's Journey *BFS,存在问题

POJ 2488 A Knight's Journey

poj2488 A Knight's Journey

A Knight's Journey POJ - 2488

POJ 2488 A Knight's Journey