您的位置:首页 > 其它

vijos1476 旅游规划-动态规划

2017-05-26 21:56 155 查看
传送门

题解:

我是这么做的,首先第一遍求出每个点向下的不相交的最长链和次长链,

这样两条链拼起来就是就是过这个点(不包含他的父亲的情况下)的最长链。

在这些最长链中取max就可以得到直径。

然后一个点在直径上,要么他本身就在已经求出的最长链上(就是从这个点出发的最长+次长链=直径长度),

要么如果这个点在某一条直径的某条链上(即这个点向父亲方向延伸的最长+这个点向下的最长=直径长度)

事实上还是要在已经求出的最长、次长和向父链上找两条最长的拼起来看是不是直径。

只不过最长肯定不会比次长短所以向父+次长就不用试了。

关于向父链的求法,假设x的某个儿子y,x的向父链为px,则

若y在x的最长链上,那么py=max(px,x的次长链)+1

否则y不在x的最长链上,py=max(px,x的最长链)+1.

最后用ans记录答案排个序即可。注意下标是从0~(n-1)不要写错。

//vijos 1476
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#define MAXN 200010
using namespace std;
vector<int> g[MAXN];int ans[MAXN],cnt;
int len1[MAXN],len2[MAXN],maxlen;
int firdfs(int rt,int fa)
{
len1[rt]=len2[rt]=0;
for(int i=g[rt].size()-1;i>=0;i--)
if(g[rt][i]!=fa)
{
firdfs(g[rt][i],rt);
len2[rt]=max(len2[rt],len1[g[rt][i]]+1);
if(len2[rt]>len1[rt]) swap(len2[rt],len1[rt]);
}
return 0;
}
int getdp(int rt,int fa,int flen)
{
// printf("%d %d\n",rt,flen);
if(len1[rt]+len2[rt]==maxlen||len1[rt]+flen==maxlen)
ans[++cnt]=rt;
for(int i=g[rt].size()-1;i>=0;i--)
if(g[rt][i]!=fa)
{
if(len1[rt]==len1[g[rt][i]]+1)
getdp(g[rt][i],rt,max(len2[rt],flen)+1);
else getdp(g[rt][i],rt,max(len1[rt],flen)+1);
}
}
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<n;i++)
{
int u,v;scanf("%d%d",&u,&v);
g[u+1].push_back(v+1);
g[v+1].push_back(u+1);
}
firdfs(5,0);
for(int i=1;i<=n;i++)
maxlen=max(maxlen,len1[i]+len2[i]);
getdp(5,0,0);
/* printf("%d\n",maxlen);
for(int i=1;i<=n;i++)
printf("%d %d\n",len1[i],len2[i]);*/
sort(ans+1,ans+cnt+1);
for(int i=1;i<=cnt;i++)
printf("%d\n",ans[i]-1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: