JZOJ 5944
题目大意
给你一棵树,可以每个点都安放定位器,
要求你放尽量少的定位器
使得任意两点(u, v)都至少有一个点 x ,使得 dst[x, u] != dst[x, v]
简单的手玩后发现,一棵以 x 为根的子树,x 有 k 个儿子
那么在 x 的子树中 至少要保证有 k - 1 个儿子的子树中有定位器
否则一定会冲突的,由于他们到 lca 距离是一定的,
那么 lca 外的子树中同深度的点就无法区分了
发现有的树会出锅,是一个定位器的祖先两端的点出问题了,
他们到定位器距离是一样的,深度是不同的,那就先强制往根放一个
这样深度不同的点就区分开了
这样 n^2 的做有 70pts
我也只会 70pts
考虑什么做法能降复杂度,并不会
要么推出来下面的性质要么找规律
可以做到 O(n) ,只要找到一个度数大于 2 的点为根,根不放,进行上边的贪心即可
考虑证明它
假设现在一棵根度数为奇数的子树中,有两点无法区分
根据深度分类讨论一下
先考虑两点深度相同的时候
由于任意一点 k 个儿子中 k - 1 个的子树都放有定位器,所以是不存在这种情况的
接下来是深度不同的情况,还要分三种情况考虑
一种是两个点在同一棵子树中
显然还至少会有一个定位器在别的子树中,将他们区分开来
一种是一个点所在的子树中没有定位器而另一个有
同上,至少会有一个定位器在别的子树中将他们区分开来
另一种是两个点所在的子树中都有定位器
如果根的度数 > 3,同上,至少会有一个定位器在别的子树中将他们区分开来
如果度数 = 3,那他们肯定是走到了 奇链中点 处,而且这个点是唯一的
所以一定还有另一个定位器,且它到两点的距离不同
所以找一个度数大于 2 的点为根 O(n) 贪心的做就好了
找不到就是链, puts(“1”);
代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cctype> #include <cstdio> using namespace std; const int MAX_N = 1000005; struct EDGE{ int nxt, to; explicit EDGE(int NXT = 0, int TO = 0) {nxt = NXT; to = TO;} }edge[MAX_N << 1]; int n, tot_edge, ans, bgn; int head[MAX_N], deg[MAX_N]; inline int rd() { register int x = 0, c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) { x = x * 10 + (c ^ 48); c = getchar(); } return x; } inline void add(int x, int y) { edge[++tot_edge] = EDGE(head[x], y); head[x] = tot_edge; ++deg[x]; edge[++tot_edge] = EDGE(head[y], x); head[y] = tot_edge; ++deg[y]; return; } bool dfs(int x, int frm) { int tot = 0; for (int i = head[x]; i; i = edge[i].nxt) if (edge[i].to != frm) { int y = edge[i].to; tot += dfs(y, x); } if (frm == 0) { if (tot < deg[x] - 1) { ans += (deg[x] - 1 - tot); tot += (deg[x] - 1 - tot); } } else if (tot < deg[x] - 2) { ans += (deg[x] - 2 - tot); tot += (deg[x] - 2 - tot); } return (tot != 0); } int main() { freopen("beacon.in", "r", stdin); freopen("beacon.out", "w", stdout); n = rd(); register int xx, yy; for (int i = 1; i < n; ++i) { xx = rd(); yy = rd(); add(xx, yy); } if (n == 1) { puts("0"); return 0; } for (int i = 1; i <= n; ++i) { if (deg[i] > 2) { bgn = i; break; } } if (!bgn) { puts("1"); return 0; } dfs(bgn, 0); printf("%d\n", ans); return 0; }
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/