Codeforces 592D Super M
来源:互联网 发布:python程序员招聘 编辑:程序博客网 时间:2024/05/01 18:15
题意:给出一颗节点数为n的树,其中有m个点必须要访问到,起点可以任意,每一次只能从当前点走到相邻点,每个点可以重复走,每走一步需要花费一个单位的时间,求把m个点走完最少需要花费的时间,并使得起点的编号最小.
分析:这道题比赛的时候并没有一点思路,赛后看了官方的题解才知道怎样做,代码写的很挫,没想到wa了一发改了一个小地方后直接AC,还是有点小激动.
1.根据观察可以发现,起点一定是m个点中的一个,很明显如果起点不是红色的点,你需要先走到一个红色的点上去.
2.如果想要走完所有的m个点,则一定会走完一颗子树,这颗子树包含这所有的m个点,换句话说这m个点可以唯一确定一颗子树
3.如果题目要求最后还要返回起点的话,可以观察出需要花费的时间 = 这颗子树的边数 * 2.
4.不需要返回,则可以在这颗子树上找到一条最长的边,也就是这棵树的直径,然后沿着这个直径访问完所有的m个点,这样需要的时间为,子树的边数*2 - 直径的边数.
5.这样问题就转化问,先求出这颗子树,然后找到一条端点尽量小的,最长的直径.
6.求树的直径有个经典思想,可以从任意一个点出发,然后dfs(bfs)找到距离该点最远的点t,再从t点出发找到一个距离t点最远的点s,则s-t就是树的直径.具体证明网上有很多,这里就不再累赘.
7.所以这里可以从任意一个红色的点出发,找到这颗子树,并找到一个距离最远且编号尽量小的端点,然后在这颗子树上在进行一次dfs就可以解决这个问题.这里只需要注意更新距离的时候同时还要考虑端点的编号大小即可.
代码:
代码写的有点挫,个人比较懒,也懒得去重构,对不住各位看官.
#include <bits/stdc++.h>using namespace std;const int maxn = 123456 + 5;vector<int> G[maxn];int n, m;int cnt;bool On[maxn];int A[maxn];int tar, d;int dis[maxn];bool vis[maxn];bool dfs1(int s){ vis[s] = true; bool flag = false; for(int i = 0; i < G[s].size(); i++) { int u = G[s][i]; if(!vis[u]) { dis[u] = dis[s] + 1; flag |= dfs1(u); } } if(A[s]) { flag = true; if(dis[s] > d || (dis[s] == d && s < tar)) { d = dis[s]; tar = s; } } if(flag) { On[s] = true; cnt++; } return flag;}void dfs2(int s){ vis[s] = true; for(int i = 0; i < G[s].size(); i++) { int u = G[s][i]; if(!vis[u] && On[u]) { dis[u] = dis[s] + 1; if(dis[u] > d || (dis[u] == d && u < tar)) { d = dis[u]; tar = u; } dfs2(u); } }}int main(){ scanf("%d%d", &n, &m); for(int i = 0; i < n - 1; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } for(int i = 0; i < m; i++) { int x; scanf("%d", &x); A[x] = true; tar = x; } fill(dis, dis + n + 1, -1); fill(vis, vis + n + 1, false); d = 0; dis[tar] = 0; dfs1(tar); int k1 = tar; fill(dis, dis + n + 1, -1); fill(vis, vis + n + 1, false); d = 0; dis[tar] = 0; dfs2(tar); int ans = min(k1, tar); printf("%d\n%d", ans, 2*(cnt-1) - d); return 0;}
0 0
- Codeforces 592D Super M
- Codeforces 592D Super M
- codeforces 592 D. Super M
- 【27.66%】【codeforces 592D】Super M
- Codeforces 592D Super M 【求解包含若干个点的最小树 + 树的直径】
- Codeforces Round #328 (Div. 2) 592 D. Super M 树的直径
- Codeforces Round #328 (Div. 2) D. Super M
- Codeforces Round #328 (Div. 2) D. Super M
- CF 592D(Super M-虚树直径)
- Codeforces Round #328 D Super M(树的直径+树形DP)
- Codeforces Round #328 (Div. 2) D. Super M (树的直径,虚树的直径)
- 最快遍历完图中重要节点 树的直径 Codeforces 328 (Div. 2) D. Super M
- codeforce #328D Super M (LCA)
- CodeForces 638D Three-dimensional Turtle Super Computer
- 【Codeforces Round 328 (Div 2)D】【树的直径 树的重心 贪心 两次dfs都找最小编号最远点】Super M 经过树上所有重要点的最小距离
- codeforces 592D 树链剖分
- Codeforces 592D
- Cf592D Super M
- 测试、文件的读写、SharedPreferences
- CF587C Duff in the Army
- 解决:ShowModalDialog中的Excel导出窗口不能自动弹出以及翻页的问题
- 关于二叉树的一些算法
- Rogue游戏(一)——游戏框架搭建
- Codeforces 592D Super M
- 《剑指offer》——字符串的排列
- Linux的设备管理,主设备号和次设备号
- 使用Canvas绘制几何图形
- 新的开始
- java多线程之run() 与start() 区别
- 第7周项目4—数组
- Android中Intent传递对象的两种方法------Serializable传值和Parcelable传值
- 《剑指offer》——合并两个排序的链表