现给出一棵N个结点二叉树,问这棵二叉树中最长链的长度为多少,保证了1号结点为二叉树的根。
输入格式
输入文件chain.in的第1行为包含了一个正整数N,为这棵二叉树的结点数,结点标号由1至N。
接下来N行,这N行中的第i行包含两个正整数l[i], r[i],表示了结点i的左儿子与右儿子编号。如果l[i]为0,表示结点i没有左儿子,同样地,如果r[i]为0则表示没有右儿子。
【样例说明】
4-2-1-3-6为这棵二叉树中的一条最长链。
【数据规模】
对于10%的数据,有N≤10;
对于40%的数据,有N≤100;
对于50%的数据,有N≤1000;
对于60%的数据,有N≤10000;
对于100%的数据,有N≤100000,且保证了树的深度不超过32768。
定义:过以节点x作为根节点的子树中,节点间的最大距离为Dis(x)。
上图,左图中Dis(根节点)最大,右图中Dis(根节点->left)最大。从上边可以看出每个节点都可能成为最大距离根节点的潜质。
因此可以求出每个Dis(节点),从中得出最大值即为整个二叉树的根节点最大值。
在求过点x的最大距离时,最大距离的两个点有可能出现在三种情况下
- 左子树
- 右子树
- 过节点x
经分析得出以下特点
- 以上三种情况最终必定一叶子结束
- 在第三种情况下必然是左子树高度 与 右子树高度 之和(只有这样,才可能取得最大值)
经过以上分析即可得出递推式
Dis(x) = max(Dis(x->left), Dis(x->right), height(x->left)+height(x->right)
--------------------------------------------------------------------------------------
维护一个数组f,f[i]表示以i节点为“最高点”的最长链的长度,左右子树都不存在时f[i]=0,否则f[i]=max(f[i的左子树],f[i的右子树])+1.
ff[i]表示以i为共同父节点的的链长度。所求为max(ff[i]) i=1~n.
a[k]、b[k]分表表示节点k的左右子树编号。
----------------------------------------------------------------------------------------
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
public class Main
{
private static Reader reader;
private static int[] a,b,f,ff;
public static void main(String[] args)
{
reader=new InputStreamReader(System.in);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=getInt();
a=new int[n+1];
b=new int[n+1];
f=new int[n+1];
ff=new int[n+1];
for(int i=1;i<=n;i++)
{
a[i]=getInt();
b[i]=getInt();
}
dfs(1);
int max=0;
for(int i=1;i<=n;i++)
{
if(a[i]>0)
ff[i]+=f[a[i]]+1;
if(b[i]>0)
ff[i]+=f[b[i]]+1;
if(ff[i]>max)
max=ff[i];
}
out.println(max);
out.flush();
}
public static void dfs(int k)
{
if(a[k]==0&&b[k]==0)
{
f[k]=0;
return ;
}
if(a[k]>0)
{
dfs(a[k]);
}
if(b[k]>0)
{
dfs(b[k]);
}
if(f[a[k]]>f[b[k]])
f[k]=f[a[k]]+1;
else
{
f[k]=f[b[k]]+1;
}
}
public static int getInt() {
int read;
int res = 0;
boolean isNegative = false;
try {
while ((read = reader.read()) != -1) {
if ((char) read == '-') {
res = 0;
isNegative = true;
break;
} else if (isNumber((char) read)) {
res = read - '0';
break;
}
}
while ((read = reader.read()) != -1) {
char ch = (char) read;
if (isNumber(ch)) {
res = res * 10 + (read - '0');
} else {
break;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (isNegative == true) {
res = -1 * res;
}
return res;
}
public static boolean isNumber(char ch) {
if (ch <= '9' && ch >= '0') {
return true;
}
return false;
}
}
数据规模较大,dfs较深爆栈,使用手工栈:
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.Stack;
public class Main
{
private static Reader reader;
private static int[] a,b,f,ff;
private static boolean[] visit;
public static void main(String[] args)
{
reader=new InputStreamReader(System.in);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=getInt();
a=new int[n+1];
b=new int[n+1];
f=new int[n+1];
ff=new int[n+1];
visit=new boolean[n+1];
for(int i=1;i<=n;i++)
{
a[i]=getInt();
b[i]=getInt();
}
dfs();
int max=0;
for(int i=1;i<=n;i++)
{
if(a[i]>0)
ff[i]+=f[a[i]]+1;
if(b[i]>0)
ff[i]+=f[b[i]]+1;
if(ff[i]>max)
max=ff[i];
}
out.println(max);
out.flush();
}
public static void dfs()
{
Stack<Integer> stack=new Stack<>();
stack.push(1);
while(!stack.isEmpty())
{
int k=stack.peek();
visit[k]=true;
if(a[k]==0&&b[k]==0)
{
f[k]=0;
stack.pop();
continue;
}
if(a[k]>0&&!visit[a[k]])
{
stack.push(a[k]);
}
if(b[k]>0&&!visit[b[k]])
{
stack.push(b[k]);
}
if(visit[a[k]]&&visit[b[k]]||(b[k]==0&&visit[a[k]])||(a[k]==0&&visit[b[k]]))
{
if(f[a[k]]>f[b[k]])
f[k]=f[a[k]]+1;
else
{
f[k]=f[b[k]]+1;
}
stack.pop();
}
}
}
public static int getInt() {
int read;
int res = 0;
boolean isNegative = false;
try {
while ((read = reader.read()) != -1) {
if ((char) read == '-') {
res = 0;
isNegative = true;
break;
} else if (isNumber((char) read)) {
res = read - '0';
break;
}
}
while ((read = reader.read()) != -1) {
char ch = (char) read;
if (isNumber(ch)) {
res = res * 10 + (read - '0');
} else {
break;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (isNegative == true) {
res = -1 * res;
}
return res;
}
public static boolean isNumber(char ch) {
if (ch <= '9' && ch >= '0') {
return true;
}
return false;
}
}