zoukankan      html  css  js  c++  java
  • [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$的值来更新答案

  • 相关阅读:
    WPF复杂形状按钮
    (WPF)360安全卫士界面设计
    WPF图标拾取器
    WPF透明窗体制作
    空间分析开源库GEOS
    GIS开源程序收集
    flask 链接 url_for()
    自定制404错误页码
    Flask 模板语言
    flask路由和视图和cookie
  • 原文地址:https://www.cnblogs.com/newera/p/9157523.html
Copyright © 2011-2022 走看看