树基础4.28

,1、常见的输入树的情况

(1)输入每个结点的父亲编号

//输入每个点的父亲 
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
#define N 10010
vector<int>vec[N];
int x,n,vis[N];
void dfs(int x){
    vis[x]=1;
    for(int i=0;i<vec[x].size();i++){
        if(!vis[vec[x][i]])dfs(vec[x][i]);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        scanf("%d",&x);
        vec[x].push_back(i);//记录每个点的儿子,x点的儿子是第i个点 
    }
    dfs(1);
    return 0;
}

(2)输入n-1条边的信息 不定根

//给出n-1条边的信息 遍历树 
#include<iostream>
#include<vector>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
#define N 10010
vector<int>vec[N];
int dad[N],x,y,n;
void dfs(int x)
{
    for(int i=0;i<vec[x].size();i++){//遍历和它相连的边 
        if(dad[x]!=vec[x][i]){
            dad[vec[x][i]]=x;
            dfs(vec[x][i]);//进行深搜; 
        }
    }
}
int main() 
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&x,&y);//储存双向边 
        vec[x].push_back(y);
        vec[y].push_back(x);
    }
    dfs(1);
    return 0;
}

2、求树的直径
树上最长的简单路径为树的直径

在树上任选一点u,以u为根进行一遍dfs,求距离u最远的点s,以s为根进行一遍dfs,找到距离s最远的点t,点s和点t之间的路径为树的直径;

//求树的直径 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
#define N 10010 
vector<int>vec[N];
int x,y,n,t,s,dis[N]; 
void dfs(int x)
{
    for(int i=0;i<vec[x].size();i++){
        if(!dis[vec[x][i]]){//没有访问过 
            dis[vec[x][i]]=dis[x]+1;//dis[vec[x][i]]到x的距离为dis[x]的距离+1 
            dfs(vec[x][i]);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        vec[x].push_back(y);
        vec[y].push_back(x);
    }
    dfs(1);//随便找一个点  
    for(int i=1;i<=n;i++){
        if(dis[i]>dis[t])t=i;//找出和它距离最大的那个点 
    }
    memset(dis,0,sizeof(dis));//一定要清0 
    dfs(t);//再找距离t最大的点 
    for(int i=1;i<=n;i++){
        if(dis[i]>dis[s])
        s=i;
    }
    printf("%d",dis[s]);//这个点到t点的距离为树的直径 
    return 0;
}

3、找到一个点,其所有的子树中最大的子树结点数最少,这个点就是这个树的重心;树的总点数为偶数时,可能会有两个重心。

先随意确定一个根,之后通过一遍dfs将所有子树的大小求出来。

如果有一个点i满足2*size i >=n,并且它的儿子都满足2*size son i <=n,那么这个点就是这个树的重心;

//求树的重心 
#include<iostream>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
#define N 10010
vector<int>vec[N];
int ans,x,y,n,sizd[N],dad[N];
void dfs(int x)
{
    size[x]=1;
    for(int i=0;i<vec[x].size();i++)
    {
        if(dad[x]!=vec[x][i])
        {
            dad[vec[x][i]]=x;
            dfs(vec[x][i]);
            size[x]+=size[vec[x][i]];//它本身的个数加上它儿子结点的个数 
        }
    }
    if(size[x]*2>=n&&!ans)//满足重心的条件 
    {
        ans=x;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        vec[x].push_back(y);//建边 
        vec[y].push_back(x);
    }
    dfs(1);//搜每个点子树结点的个数 
    printf("%d",ans);
    return 0;
} 

 

posted @ 2017-04-29 13:21  ANhour  阅读(181)  评论(0编辑  收藏  举报