首页 > vijos 1476 旅游规划题解

vijos 1476 旅游规划题解

题目链接:https://vijos.org/p/1476

解:因为这一定是一棵树,所以我们多画几次图,就会发现所有的最长路径中心点都一样,且中心点把这条最长路径分成两段等长的路。

那么做法就很简单啦,先求出图的最长路径长度(称为直径),然后找到中心点(如果最长路径长度为偶数的话,就新建一个点,连上中间的两个点,并把原来两点间的路径删去),然后做一次dfs,那些到中心点的距离为半径的,这个点包括它到中心点的路径上的点都是在最长路径上的。

求最长路径有两种方法:

1.随便取一个点为根,先做一次dfs,再找一个深度最大的点为根,再做一次dfs就可以得到最大的深度了(即为最长路径)。

2.这个有点像拓扑排序,我们每次删除都把度为1的点以及相连的边删去,直到剩下点的数目小于等于二,最后最长路径的长度即为删除的次数(删掉一批度为零的点算一次)*2+剩余的点数目。原理其实就是我们每次把最长链的两端删掉,直到没法删为止,那么删除次数*2+剩余点即为答案。

那么看一下具体程序吧。

#include
#include
#include
using namespace std;
struct ding{int to,next;
}edge[500000];
int ch,nex,cnt,maxdep2,maxdep=0,n,dep[300000],dep2[300000],head[300000],root;
bool b[300000];
void dfs(int x,int d)
{dep[x]=d;if (d>maxdep) {maxdep=d;ch=x;}for (int i=head[x];i;i=edge[i].next) if (dep[edge[i].to]==0) dfs(edge[i].to,d+1);
}
int dfs2(int x,int d)
{if (d==maxdep/2) return x;for (int i=head[x];i;i=edge[i].next)if (dep[edge[i].to]return (dfs2(edge[i].to,d+1));
}
void dfs3(int x)
{b[x]=true;for (int i=head[x];i;i=edge[i].next)
//保证那个点之前是没被更新的过,且那个点是当前点的父节点if ((!b[edge[i].to])&&(dep[edge[i].to]<dep[x]))  
dfs3(edge[i].to);
}
void add(int u,int v){edge[++cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt;}
int main()
{scanf("%d",&n);int s,t;for (int i=1;i<=n-1;i++){scanf("%d%d",&s,&t);add(s+1,t+1);add(t+1,s+1);//为了方便处理
  }dfs(1,1); int ch2=ch; ch=0;memset(dep,0,sizeof dep); maxdep=0; dfs(ch2,1);
//用两次dfs得出最长链长度int now=dfs2(ch,1);
//从链尾返回,找到中心点的前一个点
//分类讨论for (int i=head[now];i;i=edge[i].next) if (dep[edge[i].to]edge[i].to;
//nex代表当前找到的点后面的点。
//如果路的长度为偶数的话,我们就需要加边,删边,加点,这里我加了一个n +1的点if (maxdep%2==0)
{add(nex,n+1);add(n+1,nex);add(n+1,now);add(now,n+1);root=n+1;}else root=nex;
//如果长度为奇数,那么中心点就是nex
//删边if (maxdep%2==0){for (int i=head[now];i;i=edge[i].next)if (edge[edge[i].next].to==nex) {edge[i].next=edge[edge[i].next].next;break;}for (int i=head[nex];i;i=edge[i].next)if (edge[edge[i].next].to==now) {edge[i].next=edge[edge[i].next].next;break;}}
//得到半径,并进行第三次dfsint de=maxdep/2+1; maxdep=0; memset(dep,0,sizeof dep); dfs(root,1);
//如果深度等于半径的话,这条路上的点都属于最长路径,我们更新答案for (int i=1;i<=n;i++) if (dep[i]==de)  dfs3(i);for (int i=1;i<=n;i++) if (b[i]) printf("%d
",i-1);return 0;
} 

 

转载于:https://www.cnblogs.com/2014nhc/p/6624756.html

更多相关:

  • 我们在使用像QQ ,微信,微博,快手,抖音等社交软件的过程中经常需要添加好友,关注好友和被好友关注。这个过程中 这样的社交网络中的好友关系就需要被存储下来,存储在各个公司的后台服务器之上,都会作为每个公司的数据资产来进行自己核心业务的开发(视频推荐、好友推荐。。。) 这个用来保存好友关系的数据结构就是 图,接下来探索一下这个非线性数...

  • 题目地址:POJ2455 手残真浪费时间啊。。又拖到了今天才找出了错误。。每晚两道题不知不觉又变回了每晚一道题、。。sad。。 第一次在isap中忘记调用bfs,第二次则是遍历的时候竟然是从1開始遍历的。。。sad。。。 这题思路倒是非常easy,就是有一个比較坑的地方,就是这里的重边要当两条边来用,曾经受最短路什么的影响,直接把慢...

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...