树的重心与直径

树的重心

  • 树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
  • 树中所有点到某个点的距离中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。

  • 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。

  • 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。

  • 一棵树最多有两个重心,且相邻

poj1655:Balancing Act

theme:给定一棵树,求树的重心节点及删掉重心后形成的森林中最大的树的节点数。

//theme:给定一棵树,求树的重心节点及删掉重心后形成的森林中最大的树的节点数。
/*求树的重心主要是利用了DP的思想,size[x]表示以i点为根节点的子树的节点数,f[x]表示以x为根节点时,节点最多的子树节点数是多少*/
#include
#include
using namespace std;
const int N=20005;
struct edge
{
    int to,next;
}e[N*2];
int head[N],t,n,i,x,y,k,size[N],f[N],root,MIN;
inline void read(int &x)
{
    x=0; char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
inline void write(int x)
{
    if (x/10) write(x/10);
    putchar(x%10+'0');
}
inline void add(int x,int y)
{
    e[++k].to=y; e[k].next=head[x]; head[x]=k;
}
inline int max(int a,int b)
{
    return a>b?a:b;
}
inline void getroot(int now,int fa)
{
    size[now]=1; f[now]=0;
    for (int i=head[now];i!=-1;i=e[i].next)
    if (e[i].to!=fa)
    {
        getroot(e[i].to,now);
        size[now]+=size[e[i].to];
        f[now]=max(f[now],size[e[i].to]);
    }
    f[now]=max(f[now],n-size[now]);
    if (f[now]

树的直径

求法很简单,先任选一点做一次BFS,找出与它距离最远的点,那么该点就是树的直径的一个端点。  再以此端点为起点再做一次BFS,找出与它距离最远的点,那么另一个点就是树的直径的另一个端点,它们之间的距离就是树的直径。

//求树的直径,即距离最远的两点间的距离
#include
#include
using namespace std;
const int N=10005;
struct egde
{
    int to,next,v;
}e[N];
int head[N],q[N],dis[N],x,y,z,k,ans;
bool vis[N];
inline void add(int x,int y,int z)
{
    e[++k].to=y; e[k].v=z; e[k].next=head[x]; head[x]=k;
}
inline int BFS(int now)
{
    memset(vis,0,sizeof(vis));
    int H=0,T=1,num;
    vis[now]=1; dis[now]=0; q[1]=now; ans=-1;
    while (Hans) ans=dis[x],num=x;
        for (int i=head[x];i!=-1;i=e[i].next)
        if (!vis[e[i].to])
        {
            vis[e[i].to]=1;
            dis[e[i].to]=dis[x]+e[i].v;
            q[++T]=e[i].to;
        }
    }
    return num;
}
int main()
{
    memset(head,-1,sizeof(head));
    memset(e,-1,sizeof(e));
    while (scanf("%d%d%d",&x,&y,&z)!=EOF)
    add(x,y,z),add(y,x,z);
    BFS(BFS(1));
    printf("%d",ans);
    return 0;
}

E、伪直径

theme:给定一棵树,求树上不完全相同两条路径的交的长度。路径长度定义为边的长度。3<=n<=2e5

solution:其实就是求树的直径-1。而树的直径就是两遍dfs.

#include
#include
#include
using namespace std;
#define far(i,t,n) for(int i=t;iv[maxn];
int ans;

void dfs(int now,int pre,int &node,int l)
{
    if(v[now].size()==1&&v[now][0]==pre)
    {
        if(ans>n;
    int m=n-1;
    far(i,0,m)
    {
        int f,t;
        scanf("%d%d",&f,&t);
        v[f].pb(t);
        v[t].pb(f);
    }
    int node=-1;
    dfs(1,0,node,0);
    ans=0;
    int e=-1;
    dfs(node,0,e,0);
    cout<

 

你可能感兴趣的:(acm,图论)