• 洛谷 【XR-3】核心城市(树的直径,树形dp)


    传送门


    解题思路

    先考虑一个点。肯定是在树的直径的中间rt。

    树的直径就是树上距离最远的两个点的路径。

    对于树的直径求法,常用的有两种。

    1. 两遍bfs或dfs,从任意一个点开始,找到距离这个点最远的点i,再从i开始,找到距离i这个点距离最远的点j,则i、j就是树的直径的两个端点(证明略)。
    2. 树形dp也可以求。

    再推广到n个点。以rt为根,树形dp,dis[i]表示以i为根的子树的深度,即把城市i作为核心城市后,子树i中距离i最远的点到核心城市群的距离。

    然后把dis排序,删去最大的前k个,这k个就是核心城市群。然后第k+1大的dis再+1就是最终的答案。

    为什么要+1呢?因为第k+1大的dis对应的城市到核心城市群还有1的距离,所以要加1.

    AC代码

    #include<iostream> 
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cmath> 
    #include<algorithm>
    using namespace std;
    const int maxn=100005;
    int n,k,dis[maxn][3],diss[maxn],cnt,p[maxn],d1,d2,rt;
    struct node{
        int v,next;
    }e[maxn*2];
    void insert(int u,int v){
        cnt++;
        e[cnt].next=p[u];
        e[cnt].v=v;
        p[u]=cnt;
    }
    int dfs(int u,int id){
        int ans;
        queue<int> q;
        dis[u][id]=0;
        q.push(u);
        while(!q.empty()){
            u=q.front();
            q.pop();
            if(q.empty()){
                ans=u;
            }
            for(int i=p[u];i!=-1;i=e[i].next){
                int v=e[i].v;
                if(!dis[v][id]){
                    dis[v][id]=dis[u][id]+1;
                    q.push(v);
                }
            }
        }
        return ans;
    }
    void findd(){
        d1=dfs(1,0);
        d2=dfs(d1,1);
        for(int i=1;i<=n;i++){
            if(abs(dis[i][0]-dis[i][1])<=1){
                rt=i;
                break;
            }
        }
    }
    void dfs2(int u,int fa){
        for(int i=p[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(v==fa) continue;
            dfs2(v,u);
            diss[u]=max(diss[u],diss[v]+1);
        }
    }
    int main(){
        memset(p,-1,sizeof(p));
        cin>>n>>k;
        for(int i=1;i<n;i++){
            int u,v;
            cin>>u>>v;
            insert(u,v);
            insert(v,u);
        }
        findd();
        dfs2(rt,-1);
        sort(diss+1,diss+n+1);
        cout<<diss[n-k]+1<<endl;
        return 0;
    }
  • 相关阅读:
    在C#中使用正则表达式
    C++流操纵算子(格式控制)
    linux(Fedora) doxygen 的安装和使用
    UTF8
    java cookie全解析
    Fedora16 安装Adobe Flash Player方法
    工程素养
    感悟数据封装
    谷歌如何保护隐私
    openCV画的词法分析图
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/13663543.html
Copyright © 2020-2023  润新知