• Codeforces Round #328 (Div. 2) D. Super M


    题目链接:

    http://codeforces.com/contest/592/problem/D

    题意:

    给你一颗树,树上有一些必须访问的节点,你可以任选一个起点,依次访问所有的必须访问的节点,使总路程最短。

    题解:

    由于是树,任意两点间路径唯一,是确定的。

    首先我们要先建一颗树:包括所有必须访问的节点,已经它们之间的路径。

    我们选的起点一定是某个必须访问的节点,如果我们把所有的必须访问的节点访问一遍并且回到起点,那么我们用的最小花费就是边数*2(这个可以用反证法证明),所以只要我们找出新树的直径,答案就是边数*2-直径。

    (官方题解)

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    
    const int maxn = 2e5 + 10;
    const int INF = 0x3f3f3f3f;
    
    int n, m;
    vector<int> G[maxn];
    int ans,ans1,ans2,dis;
    bool tag[maxn];
    
    //两次dfs求最远顶点对
    void dfs(int u,int fa,int d,int& res) {
        if (dis < d&&tag[u]) {
            dis = max(dis, d);
            res = u;
        }
        if (dis == d&&tag[u]) res = min(res, u);
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if (v == fa) continue;
            dfs(v, u, d + 1, res);
        }
    }
    
    bool used[maxn];
    int _cnt;
    //求虚拟树的节点数
    bool dfs2(int u, int fa) {
        if (tag[u]) used[u]=1;
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if (v == fa) continue;
            used[u] |= dfs2(v, u);
        }
        if (used[u]) _cnt++;
        return used[u];
    }
    
    int main() {
        memset(tag, 0, sizeof(tag));
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        ans = INF;
        for (int i = 0; i < m; i++) {
            int v;
            scanf("%d", &v);
            tag[v] = 1;
            ans = min(ans, v);
        }
        if (m == 1) {
            printf("%d
    %d
    ", ans, 0);
            return 0;
        }
        dis = -1, ans1 = INF;
        dfs(ans, -1, 0,ans1);
        dis = -1, ans2 = INF;
        dfs(ans1, -1, 0, ans2);
    
        memset(used, 0, sizeof(used));
        _cnt = 0;
        dfs2(ans1, -1);
        int res = (_cnt - 1) * 2 - dis;
        printf("%d
    %d
    ", min(ans1, ans2), res);
        return 0;
    }
  • 相关阅读:
    2019 SDN上机第2次作业
    2019 SDN上机第1次作业
    第07组 团队Git现场编程实战
    第二次结对编程作业
    c语言之问题集
    2019春第2次课程设计实验安排
    2019年十二周总结
    第十一周总结
    第十周作业
    第九周总结
  • 原文地址:https://www.cnblogs.com/fenice/p/5572432.html
Copyright © 2020-2023  润新知