求一棵树的最小路径覆盖
相关题目:http://codeforces.com/problemset/problem/618/D
有向图的最小路径覆盖(所有点)可以用二分图来解,n-最大匹配。
无向图的最小路径覆盖(所有点)似乎是比较困难的问题
那么对于特殊的无向图 - '树'来说,求它的最小路径覆盖有什么好用的方法呢?
首先我们可以考虑用dp求解,维护每棵子树留下向上可延伸路径的情况下能获得的最小路径覆盖是多少f[i][1],以及每棵子树不留下向上可延伸路径的情况下能获得的最小路径覆盖f[i][0]。转移在这里不多赘述,但是有一点是显而易见的,对于每个点i,f[i][0]≥f[i][1]。而这一点恰好可以给我们一点新的想法,是否可以每个点尽量“不留后路”,也就是说能“能拐下去则拐下去”?答案是肯定的。
首先应明确一点,求最小路径覆盖,也就是使路径覆盖尽量多的边。
我们对于每个点,找到它孩子中“可延伸”的个数tot,如果tot=0,那么这个点只能成为“可延伸”点,如果tot=1,那么这唯一一条由儿子延伸上来的边一定要加入答案U的,同时当前这个点也成为了“可延伸”点,如果tot≥2那么这个点可以合任意两个儿子延伸上来的边“为一”,将两条边加入答案U,这样路径数无形中减了1,这也验证了贪心的正确性,因为如果不合二为一的话,此时答案不会更优,那么继续往上延伸后的结果最好也就是-1,早减晚减都一样,还不如早减,免得“过了这村没这店”了。
最后DFS结束,得到了答案U,答案U实际上是最多覆盖多少条边。那么最小路径也就是n-U了。
void Dfs(int x, int fa) { int ed = last[x], dr; int tot = 0; while (ed != -1) { dr = other[ed]; if (dr != fa) { Dfs(dr, x); if (flag[dr]) tot++; } ed = pre[ed]; } if (tot == 0) flag[x] = true; else if (tot == 1) cnt++, flag[x] = true; else cnt += 2LL, flag[x] = false; }