码迷,mamicode.com
首页 > 其他好文 > 详细

[POJ 1935] Journey

时间:2018-06-08 22:04:34      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:距离   continue   efi   关键点   i++   ring   因此   namespace   tar   

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

标签:距离   continue   efi   关键点   i++   ring   因此   namespace   tar   

原文地址:https://www.cnblogs.com/newera/p/9157523.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!