【poj1655】【poj3107】【求树的重心】

先来说一下怎样来求树的直径:

假设 s-t这条路径为树的直径,或者称为树上的最长路

现有结论,从任意一点u出发搜到的最远的点一定是s、t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路

证明:

1 设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T则

dis(u,T) >dis(u,s) 且 dis(u,T)>dis(u,t) 则最长路不是s-t了,与假设矛盾

2 设u不为s-t路径上的点

首先明确,假如u走到了s-t路径上的一点,那么接下来的路径肯定都在s-t上了,而且终点为s或t,在1中已经证明过了

所以现在又有两种情况了:

1:u走到了s-t路径上的某点,假设为X,最后肯定走到某个端点,假设是t ,则路径总长度为dis(u,X)+dis(X,t)

2:u走到最远点的路径u-T与s-t无交点,则dis(u-T) >dis(u,X)+dis(X,t);显然,如果这个式子成立,

则dis(u,T)+dis(s,X)+dis(u,X)>dis(s,X)+dis(X,t)=dis(s,t)最长路不是s-t矛盾

然后对于树的重心的求法其实跟上面的情况类似:

我们用son[i]来记录i的子节点的数目,balance为删除节点i时的最大的节点数时多少。

那么我们就可以知道,balance=max(son[j]+1,n-son[x]-1)

j∈i的子节点。

然后我们dfs一遍就可以在n的时间内求出树的重心了。

Balancing Act

Time Limit: 1000MS Memory Limit: 65536K

Total Submissions: 9890 Accepted: 4063

Description

Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1…N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the largest tree in the forest T created by deleting that node from T.

For example, consider the tree:

Deleting node 4 yields two trees whose member nodes are {5} and {1,2,3,6,7}. The larger of these two trees has five nodes, thus the balance of node 4 is five. Deleting node 1 yields a forest of three trees of equal size: {2,6}, {3,7}, and {4,5}. Each of these trees has two nodes, so the balance of node 1 is two.

For each input tree, calculate the node that has the minimum balance. If multiple nodes have equal balance, output the one with the lowest number.

Input

The first line of input contains a single integer t (1 <= t <= 20), the number of test cases. The first line of each test case contains an integer N (1 <= N <= 20,000), the number of congruence. The next N-1 lines each contains two space-separated node numbers that are the endpoints of an edge in the tree. No edge will be listed twice, and all edges will be listed.

Output

For each test case, print a line containing two integers, the number of the node with minimum balance and the balance of that node.

Sample Input

1

7

2 6

1 2

1 4

4 5

3 7

3 1

Sample Output

1 2

题意就是要求出树的重心和重心节点的编号,输出时编号在前。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=20010;
const int inf=2100000000LL;
vector <int> a[N];
int t,son[N],n,No,ans;
bool f[N];
int in()
{
    int x=0;
    char ch;
    ch=getchar();
    while(ch<‘0‘||ch>‘9‘) ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x;
}
void dfs(int x)
{
    int i,j,u,balance=0;
    son[x]=0;
    f[x]=false;
    for(i=0;i<a[x].size();++i){
        u=a[x][i];
        if(!f[u]) continue;
        dfs(u);
        son[x]+=son[u]+1;
        balance=max(balance,son[u]+1);
    }
    balance=max(balance,n-son[x]-1);
    if(balance<ans||(balance==ans&&No<x)){
        ans=balance;
        No=x;
    }
}
int main()
{
    t=in();
    while(t--){
        int i,j,x,y;
        n=in();
        ans=inf;
        memset(f,1,sizeof(f));
        for(i=1;i<=n;++i) a[i].clear();
        for(i=1;i<n;++i){
            x=in();y=in();
            a[x].push_back(y);
            a[y].push_back(x);
        }
        dfs(1);
        printf("%d %d\n",No,ans);
    }
}

Godfather

Time Limit: 2000MS Memory Limit: 65536K

Total Submissions: 5061 Accepted: 1767

Description

Last years Chicago was full of gangster fights and strange murders. The chief of the police got really tired of all these crimes, and decided to arrest the mafia leaders.

Unfortunately, the structure of Chicago mafia is rather complicated. There are n persons known to be related to mafia. The police have traced their activity for some time, and know that some of them are communicating with each other. Based on the data collected, the chief of the police suggests that the mafia hierarchy can be represented as a tree. The head of the mafia, Godfather, is the root of the tree, and if some person is represented by a node in the tree, its direct subordinates are represented by the children of that node. For the purpose of conspiracy the gangsters only communicate with their direct subordinates and their direct master.

Unfortunately, though the police know gangsters’ communications, they do not know who is a master in any pair of communicating persons. Thus they only have an undirected tree of communications, and do not know who Godfather is.

Based on the idea that Godfather wants to have the most possible control over mafia, the chief of the police has made a suggestion that Godfather is such a person that after deleting it from the communications tree the size of the largest remaining connected component is as small as possible. Help the police to find all potential Godfathers and they will arrest them.

Input

The first line of the input file contains n — the number of persons suspected to belong to mafia (2 ≤ n ≤ 50 000). Let them be numbered from 1 to n.

The following n ? 1 lines contain two integer numbers each. The pair ai, bi means that the gangster ai has communicated with the gangster bi. It is guaranteed that the gangsters’ communications form a tree.

Output

Print the numbers of all persons that are suspected to be Godfather. The numbers must be printed in the increasing order, separated by spaces.

Sample Input

6

1 2

2 3

2 5

3 4

3 6

Sample Output

2 3

这个题是要求求出这个树上的所有重心,并按照节点的编号从小到大输出。

值得注意的是,这道题如果用stl会T,所以我用了next数组

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=50010;
const int inf=210000000;
int point[N],next[N*10],n,tot=1,minn,ans[N],son[N];
bool f[N];
struct s{
    int st,en;
}aa[N*10];
void add(int x,int y)
{
    tot+=1;next[tot]=point[x];point[x]=tot;
    aa[tot].st=x;aa[tot].en=y;
}
void dfs(int x)
{
    int u,balance=0,i;
    f[x]=false;
    son[x]=0;
    for(i=point[x];i;i=next[i]){
        u=aa[i].en;
        if(!f[u]) continue;
        dfs(u);
        son[x]+=son[u]+1;
        balance=max(balance,son[u]+1);
    }
    balance=max(balance,n-son[x]-1);
    if(balance<minn){
        ans[0]=1;
        ans[1]=x;
        minn=balance;
    }
    else if(balance==minn){
        ans[0]+=1;
        ans[ans[0]]=x;
    }
}
int main()
{
    int i,j,x,y;
    scanf("%d",&n);
    memset(f,1,sizeof(f));
    for(i=1;i<n;++i){
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    minn=inf;
    dfs(1);
    sort(ans+1,ans+ans[0]+1);
    for(i=1;i<=ans[0];++i)
      printf("%d ",ans[i]);
    printf("\n");
}
时间: 2024-08-06 19:38:21

【poj1655】【poj3107】【求树的重心】的相关文章

poj1655 Balancing Act 求树的重心

http://poj.org/problem?id=1655 Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9072   Accepted: 3765 Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a fo

51nod 配对(求树的重心)

传送门:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737 给出一棵n个点的树,将这n个点两两配对,求所有可行的方案中配对两点间的距离的总和最大为多少. Input 一个数n(1<=n<=100,000,n保证为偶数) 接下来n-1行每行三个数x,y,z表示有一条长度为z的边连接x和y(0<=z<=1,000,000,000) Output 一个数表示答案 Input示例 6 1 2 1 1 3 1

POJ 1655 Balancing Act (求树的重心)

求树的重心,直接当模板吧.先看POJ题目就知道重心什么意思了... 重心:删除该节点后最大连通块的节点数目最小 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<queue> 5 #include<stack> 6 using namespace std; 7 #define LL long long 8 #define clc(a,b) memset(a

POJ 1655 Balancing Act(求树的重心)

题目大意: 就是要求树的重心,重心的定义就是删除这个点使得森林尽量平衡. 也可以让分治子树的时候使得每颗子树的数量在nlogn以内. 思路分析: son [x] 表示x的子树的数量  不包括自己. balance 表示最大的森林的节点数. 最后我们要让最大的balance 最小. balance = max (balance ,n - 1 - son[x]  , son[j] +1).. #include <cstdio> #include <iostream> #include

树形DP求树的重心 --SGU 134

令一个点的属性值为:去除这个点以及与这个点相连的所有边后得到的连通分量的节点数的最大值. 则树的重心定义为:一个点,这个点的属性值在所有点中是最小的. SGU 134 即要找出所有的重心,并且找出重心的属性值. 考虑用树形DP. dp[u]表示割去u点,得到的连通分支的节点数的最大值. tot[u]记录以u为根的这棵子树的节点数总和(包括根). 则用一次dfs即可预处理出这两个数组.再枚举每个点,每个点的属性值其实为max(dp[u],n-tot[u]),因为有可能最大的连通分支在u的父亲及以上

树形dp求树的重心

Balancing Act http://poj.org/problem?id=1655 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #define mt(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 const int M=50010; 8 vector<int> g[

POJ 1655 Balancing Act(求树的重心--树形DP)

题意:求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的. 思路:随便选一个点把无根图转化成有根图,dfs一遍即可dp出答案 //1348K 125MS C++ 1127B #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; int

poj 1655 Balancing Act 求树的重心【树形dp】

poj 1655 Balancing Act 题意:求树的重心且编号数最小 一棵树的重心是指一个结点u,去掉它后剩下的子树结点数最少. (图片来源: PatrickZhou 感谢博主) 看上面的图就好明白了,不仅要考虑当前结点子树的大小,也要"向上"考虑树的大小. 那么其它就dfs完成就行了,son[] 存以前结点为根的结点个数. 这是用邻接表写: 1 #include<iostream> 2 #include<cstdio> 3 #include<cst

求树的重心

给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的. 首先要知道什么是树的重心,树的重心定义为:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重 心后,生成的多棵树尽可能平衡.  实际上树的重心在树的点分治中有重要的作用, 可以避免N^2的极端复杂度(从退化链的一端出发) 算法就是跑一遍dfs,找到最优解. 链接 代码: #include <iostream> #include <string.h