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;
}
题解:
我是这么做的,首先第一遍求出每个点向下的不相交的最长链和次长链,
这样两条链拼起来就是就是过这个点(不包含他的父亲的情况下)的最长链。
在这些最长链中取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;
}
相关文章推荐
- [vijos1476]旅游规划(csapc)(树形dp)
- 【动态规划】Vijos P1680 距离
- 【动态规划】【二分】【最长上升子序列】Vijos P1028 魔族密码
- vijos1057【动态规划】
- VIJOS-P1327 回文词(动态规划)
- 【动态规划】【最长公共子序列】Vijos P1111 小胖的水果
- 【动态规划】Vijos P1313 金明的预算方案(NOIP2006提高组第二题)
- 【动态规划】Vijos P1616 迎接仪式
- [20] Vijos P1737 选择客栈(动态规划,方案数)
- 动态规划Always On the Run poj 1476解题报告(附详细分析)
- Vijos 1069 新年趣事之红包(动态规划最短路)
- vijos & codevs 能量项链 - 动态规划
- vijos1059【动态规划】
- Vijos[1982]NOIP2015Day2T2 子串 substring 动态规划
- Vijos - 1037 搭建双塔 动态规划(DP) 重庆一中高2018级竞赛班第七次测试 2016.8.4 Problem 2
- |Vijos|NOIP2002|动态规划|P1121 马拦过河卒
- VIJOS P1057盖房子 (动态规划)
- 【动态规划】【归并】Vijos P1412 多人背包
- Vijos P1121 马拦过河卒(动态规划)
- Vijos P1775 乌龟棋(动态规划,四维)