先来说一下怎样来求树的直径:
假设 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");
}