CF14E Camels

(暑假的CF模拟赛)

这是我感觉最难的题

一开始以为要先跑一遍树的直径,然后在剩下可以选的点里跑最长的。

经过几分钟沉思后发现这方法不对……

例如:

考虑换一种方法,枚举一个断边,将原树分开的两子树分别跑直径,然后直径相乘就可以求出答案。

(求直径我写的dp,赛事遗忘bfs求直径如何打)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
long long head[305],ans,a,b,fk;
struct hehe
{
	long long w,syg;
}lsqxx[605];
void add(long long t,long long w)
{
	ans++;
	lsqxx[ans].w=w;
	lsqxx[ans].syg=head[t];
	head[t]=ans;
}
long long n,zc;
long long zj(long long wz,long long bb)//求直径函数 
{
	long long daan=0,cd1=0,cd2=0;//cd1,cd2分别代表子树中深的最大值和次大值 
	for(int i=head[wz];i!=0;i=lsqxx[i].syg)
	{
		if(lsqxx[i].w==bb)
		{
			continue;
		}
		daan=max(daan,zj(lsqxx[i].w,wz));//具体思想,zc为向下搜后的最大值,如果比现在的最大值大,就替换,现在的次大值变为之前的最大值 
		if(zc>cd1)
		{
			cd2=cd1;
			cd1=zc;
		}else
		{
			cd2=max(cd2,zc);//如果zc没最大值大,就看看能否替换次大值 
		}
	}
	daan=max(daan,cd1+cd2);//然后就可以求出直径 
	zc=cd1+1;
	return daan;
}
int main()
{
	scanf("%lld",&n);
	for(int i=1;i<n;i++)
	{
		scanf("%lld%lld",&a,&b);
		add(a,b);
		add(b,a);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=head[i];j!=0;j=lsqxx[j].syg)//断边 
		{
			zc=0;
			long long aa=zj(i,lsqxx[j].w);
			zc=0;
			long long aaa=zj(lsqxx[j].w,i);
			fk=max(fk,aa*aaa);
		}
	}
	printf("%lld
",fk);
	return 0;
}

  

原文地址:https://www.cnblogs.com/lichangjian/p/14989644.html