zoukankan      html  css  js  c++  java
  • 核心城市

    洛咕

    题意:给定一棵n个节点的树,每条边的长度为1,钦定k个节点为核心节点,这k个节点要满足两个条件:

    1.这k座城市可以通过边,在不经过其他节点的情况下两两相互到达.

    2.定义某个非核心节点与这k个核心节点的距离为这个节点与k个核心节点的距离的最小值,那么所有非核心节点中,与核心节点的距离最大的节点,其与核心节点的距离最小.你需要求出这个最小值.

    因为我是通过搜索标签搜到这道题的,所以一开始就往"树的直径"上面想了.这k个节点必定是树的直径上的一段,且k个节点的中点就是树的直径的中点.

    所以我们先两次(DFS)找出树的直径,第二次(DFS)时通过记录路径(pre),找到树的直径的中点.然后以这个中点为根再一次(DFS),处理出(dis[i])表示根节点到节点i的距离,(dist[i])表示以节点i为根的子树中,从i出发能够到达的最远距离.

    然后我们把所有节点按照(dist[i]-dis[i])从大到小排序,前k个就是所谓核心节点了.

    因为各种各样的原因,这道题我压行了,因为我发现不压行的话代码又长又丑,压行的话只是丑一点...

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=1e5+5;
    int dis[N],pre[N],a[N],c[N],dist[N],bj[N];
    int tot,head[N],nxt[N<<1],to[N<<1];
    struct ppx{int val,id;}b[N];
    inline bool cmp(ppx x,ppx y){return x.val>y.val;}
    inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
    inline void dfs1(int u,int fa){
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(v==fa)continue;
    		dis[v]=dis[u]+1;dfs1(v,u);
    	}
    }
    inline void dfs2(int u,int fa){
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(v==fa)continue;
    		dis[v]=dis[u]+1;pre[v]=u;dfs2(v,u);
    	}
    }
    inline void dfs3(int u,int fa){
    	dist[u]=dis[u];
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];if(v==fa)continue;
    		dis[v]=dis[u]+1;dfs3(v,u);
    		dist[u]=max(dist[u],dist[v]);
    	}
    }
    int main(){
    	int n=read(),k=read();
    	for(int i=1;i<n;++i){int a=read(),b=read();add(a,b);add(b,a);}//存图
    	dfs1(1,0);int maxn=0,pos1,pos2;//第一次以任意一个节点为根dfs
    	for(int i=1;i<=n;++i)if(dis[i]>maxn){maxn=dis[i];pos1=i;}//找到距离最远的那个点pos1
    	memset(dis,0,sizeof(dis));dfs2(pos1,0);maxn=0;//以pos1为根第二次dfs
    	for(int i=1;i<=n;++i)if(dis[i]>maxn){maxn=dis[i];pos2=i;}//找到距离最远的那个节点pos2,此时pos1-pos2就是树的直径
    	int tot=0;while(pos2!=pos1){a[++tot]=pos2;pos2=pre[pos2];}//递归存储直径上的所有节点
    	a[++tot]=pos1;reverse(a+1,a+tot+1);
    	int root=a[(tot+1)/2];memset(dis,0,sizeof(dis));dfs3(root,0);//找到中点,以其为根dfs
    	for(int i=1;i<=n;++i){
    		b[i].val=dist[i]-dis[i];
    		b[i].id=i;c[i]=b[i].val;
    	}
    	sort(b+1,b+n+1,cmp);
    	for(int i=1;i<=k;++i)bj[b[i].id]=1;//选出k个核心节点
    	int ans=0;
    	for(int i=1;i<=n;++i)
    		if(!bj[i])ans=max(c[i]+1,ans);//不是核心节点,就计算贡献
    	printf("%d
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    C#图形编程
    深入浅出话事件(上)
    .NET名称空间对应的类集
    Equals() 和运算符 == 的重写准则(C# 编程指南)
    Implement EventArgs
    CLS(公共语言规范)的CLSCompliant(跨语言调用)
    学习MSCOREE.dll是托管程序的入口点
    设计模式之原型模式代码示例
    The disk cannot be added to Cluster Shared Volumes because it does not have any suitable partitions
    RAID小结
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11563524.html
Copyright © 2011-2022 走看看