• 树的直径和重心


    树的重心

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=50010;//常量 
    struct use{
        int st,en;//st为起点,en 为终点 
    }b[1000001];//存储边信息 
    int son[N],n,ans[N],minn,next[5000001]={0},point[100001]={0},tot;
    //son记录最大子节点树,下标表示结点的值 
    bool f[N];
    //通讯图的构建:创建边的起点和终点 
    void add(int x,int y){
        tot++; //记录边的编号 
    	next[tot]=point[x]; //表示与当前tot边同一起点x的上一条边的编号
    	point[x]=tot; //point存储当前点的最后一条连接边 
        b[tot].st=x; //边的起点是x  
    	b[tot].en=y; //边的终点是y 
    	return;
    }
    //深搜:查找以结点x为起点的所有结点的子树结点数 
    void dfs(int x){//x为结点值 
        int u,balance=0;
        son[x]=0;
        f[x]=false; //标记为false的点,避免双向边重复记录结点数 
        for(int i=point[x];i;i=next[i]){
            u=b[i].en;  //边的终点 
            if(!f[u]) 	//点u被标记为false 
    			continue; //跳过本层循环,继续查找下一个子节点 
            dfs(u); //找到新的根节点,继续深搜 
            son[x]+=son[u]+1;   //子节点数=儿子的子节点数+1(本身)
            //balance表示以结点i为父亲的子树中,结点个数的最大值 
    		balance=max(balance,son[u]+1);
        }
        //还有一棵由原根节点为根的树,它的节点数就是原树总结点数-(被取点的儿子树+1)
        balance=max(balance,n-son[x]-1);
        //ans存放重心结点编号,ans[0]记录重心的个数 
        if(balance<minn){
            minn=balance;
            ans[0]=1;
            ans[1]=x;
        }
        else if(balance==minn){
            ans[0]+=1;
            ans[ans[0]]=x;
        }
        return;
    }
    int main(){
        int x,y;
        cin>>n;
        minn=1000001;
        memset(f,1,sizeof(f)); //初始化函数,将f中的内容全部设置为1 
        for(int i=1;i<n;i++){ //输入n个点的(n-1)条边 
            cin>>x>>y; 
            //添加双向边 
            add(x,y);
            add(y,x);        
        }
        //从任意一个点开始深搜,进行每个结点的子树结点数【balance】统计 
        dfs(1);
        sort(ans+1,ans+ans[0]+1);
        for(int i=1;i<=ans[0];i++) 
          cout<<ans[i]<<" ";
        cout<<endl;
        return 0; 
    }
    
    /*
    6
    1 2
    2 3
    2 5
    3 4
    3 6
    */
    

    树的直径

        #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=100001;
    //创建边结构体--有两个端点属性 
    struct node{
        int to,next;//next 存从起点出发的上一条边的下标  to到那个结点 
    }edge[maxn];
    int cnt=1; //记录边的编号 
    int vis[maxn],head[maxn],dis[maxn];
    //添加边--传入边的起点和终点 
    void add(int u,int v){
    	cnt++; //记录边的编号 
        edge[cnt].to=v; //记录边指向点V 
        edge[cnt].next=head[u]; //***记录边的上一条边
        head[u]=cnt; //存储以u出发的新加入的边的编号 
    }
    void dfs(int x){
        vis[x]=1; //当前结点参与了深搜过程,则被标记 
        //循环执行以x为起点的所有条边-->从最后加入的边开始,到最先加入的边结束 
        for(int i=head[x];i;i=edge[i].next){
            if(!vis[edge[i].to]){ //如果这条边的终点未被记录过,则计数并继续深搜 
                dis[edge[i].to]=dis[x]+1; //当前点的边权加一 
                dfs(edge[i].to); //继续深搜 
            }
        }
    }
    int main(){
    	//输入点的数量 
        int n;
        cin>>n;
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(dis,0,sizeof(dis));
        //创建边 
        for(int i=1;i<n;i++){
            int u,v;
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }
        dis[1]=1;
        //第一次深搜 
        dfs(1);
        int pos=1;
        //找到树直径的一个端点 
        for(int i=1;i<=n;i++){
            if(dis[i]>dis[pos])
            pos=i;
        }
        memset(vis,0,sizeof(vis));
        dis[pos]=1;
        //第二次深搜 
        dfs(pos);
        //找到另一个端点 ,以及两个端点之间的最远距离 
        int ans=0;
        for(int i=1;i<=n;i++){
           	if(dis[i]>ans)
               ans=dis[i];
        }
        cout<<ans;
        return 0; 
    }
    
    
  • 相关阅读:
    【原】React操作表单
    【原】使用webpack打包的后,公共请求路径的配置问题
    【原】React中,map出来的元素添加事件无法使用
    codeforces 1288C. Two Arrays(dp)
    Educational Codeforces Round 80 A-E简要题解
    HDU 2586 ( LCA/tarjan算法模板)
    POJ 1330(LCA/倍增法模板)
    POJ 3368 (ST表)
    POJ 3264 Balanced Lineup(ST模板)
    codeforces 1285E. Delete a Segment
  • 原文地址:https://www.cnblogs.com/limoyun/p/16366223.html
Copyright © 2020-2023  润新知