zoukankan      html  css  js  c++  java
  • Codeforces 1004E

    题意略。

    思路:

    这k个点应该放在这棵树的直径上,并且能连成一条路径。如果k比树的直径上的点要多,那么我们就不用把这k个点都用上,

    只需要把这棵树直径上所有的点都覆盖上就行了。如果k比树的直径上的点要少,那么我们尽量使这k个点放在这个直径的中心位置。

                                                                             

    这个我们可以简单说一下:

    首先,把这k个点放在直径中央可以保证直径上的点到这段路径的最大距离最小。但是其他的枝叶呢,可以保证其他枝叶上的点到这一段路径的最大距离最小吗?

    假设我为了迁就某个枝叶上的点,使得这段路径偏离了直径的中央,那么只能说明这段枝叶比原来接口处向外的那一部分直径还长,这是不可能的,

    这只能说明这段枝叶是直径的一部分。

    所以我们先找出直径,再寻找直径的中间位置,然后一遍dfs,确定整棵树上到这段路径的最远距离。

    详见代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 100005;
    
    struct edge{
        int to,w;
        edge(int a = 0,int b = 0){
            to = a,w = b;
        }
    };
    
    int deep[maxn],fa[maxn],store[maxn],tail,n,k;
    vector<edge> graph[maxn];
    
    void dfs(int node){
        for(int i = 0;i < graph[node].size();++i){
            edge e = graph[node][i];
            int to = e.to,w = e.w;
            if(fa[to] == 0){
                if(deep[to] == -1) deep[to] = deep[node] + w;
                fa[to] = node;
                dfs(to);
            }
        }
    }
    
    int main(){
        scanf("%d%d",&n,&k);
        int from,to,w;
        for(int i = 0;i < n - 1;++i){
            scanf("%d%d%d",&from,&to,&w);
            graph[from].push_back(edge(to,w));
            graph[to].push_back(edge(from,w));
        }
        memset(deep,-1,sizeof(deep));
        memset(fa,0,sizeof(fa));
        fa[1] = -1;
        deep[1] = 0;
        dfs(1);
        int ed1 = 1,ed2;
        for(int i = 1;i <= n;++i){
            if(deep[i] > deep[ed1]) ed1 = i;
        }
        memset(deep,-1,sizeof(deep));
        memset(fa,0,sizeof(fa));
        fa[ed1] = -1;
        deep[ed1] = 0;
        dfs(ed1);
        ed2 = ed1;
        for(int i = 1;i <= n;++i){
            if(deep[i] > deep[ed2]) ed2 = i;
        }
        int deepest = deep[ed2];
        for(int i = ed2;i != -1;i = fa[i]){
            store[tail++] = i;
        }
        
        int l,r;
        if(tail <= k) l = 0,r = tail - 1;
        else{
            int L = 0;
            for(int i = 0;i < tail - k + 1;++i){
                if(max(deepest - deep[store[i]],deep[store[i + k - 1]]) < max(deepest - deep[store[L]],deep[store[L + k - 1]]))
                    L = i;
            }
            l = L,r = l + k - 1;
        }
        memset(deep,-1,sizeof(deep));
        memset(fa,0,sizeof(fa));
        fa[store[l]] = -1;
        for(int i = l;i <= r;++i){
            deep[store[i]] = 0;
        }
        dfs(store[l]);
        int ans = 0;
        for(int i = 1;i <= n;++i) ans = max(ans,deep[i]);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    ffmpeg mp4 视频输出为 aac 的命令
    git操作远程分支
    Linux (openSUSE 15.3 ) server ssh 可以使用,sftp无法使用
    小小思考题
    Linux 命令介绍
    2021 年 如何使用VMware 安装 ubuntu 7.04 虚拟机, 配置 apt 源
    Linux 下 命令行 使用浏览器
    oracle.cmd
    Sqlcmd
    vue eslint 配置使用
  • 原文地址:https://www.cnblogs.com/tiberius/p/9287703.html
Copyright © 2011-2022 走看看