【ZOJ月赛】【树形DP】【I.Destroy】
2013-01-22 22:30
357 查看
【题目来源】http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=4937
【个人体会】这个题目刚开始看的时候我以为是树的中心点+最小割。但是最小割那边我很怕会超时,因此一开始就没敢打,后来发现可以使用树形DP在O(N)的级别中解决这个问题,因此思路很明确,首先是求树的中心点,然后是树形DP,总级别也是O(N),可能带点常数,但无关紧要。
【题目解析】思路分为两块,第一块是求树的中心点,有经典的O(N)级别的算法。第二块是树形DP,DP[U]表示的是以U为根的子树中,切断所有叶子节点与根节点的联系,所要付出的那个最大边的代价。因此,对于U和U的某个儿子V,在cost[U,V]和DP(V)中选一个小的,记为min{cost[U,V], DP(V)},最后在所有的min{cost[U,V], DP(V)}中选一个max用来更新DP(U)
【代码如下】
【个人体会】这个题目刚开始看的时候我以为是树的中心点+最小割。但是最小割那边我很怕会超时,因此一开始就没敢打,后来发现可以使用树形DP在O(N)的级别中解决这个问题,因此思路很明确,首先是求树的中心点,然后是树形DP,总级别也是O(N),可能带点常数,但无关紧要。
【题目解析】思路分为两块,第一块是求树的中心点,有经典的O(N)级别的算法。第二块是树形DP,DP[U]表示的是以U为根的子树中,切断所有叶子节点与根节点的联系,所要付出的那个最大边的代价。因此,对于U和U的某个儿子V,在cost[U,V]和DP(V)中选一个小的,记为min{cost[U,V], DP(V)},最后在所有的min{cost[U,V], DP(V)}中选一个max用来更新DP(U)
【代码如下】
#include <iostream> #include <cstdio> #include <climits> #include <cstdlib> #include <cstring> #include <vector> #include <deque> #include <stack> #include <queue> #include <algorithm> #define rep(i, x) for (int i = 1; i <= x; ++i) #define rept(i, x) for (int i = 0; i < x; ++i) #define pb push_back #define ppf pop_front #define mp make_pair #define pf push_front #define x first #define y second #define FILE_IO #define DEBUG using namespace std; typedef long long int64; const int Max = 10001, MAX = 1e16 + 1; struct edge { int v, c, next; int64 w; }E[Max * 2]; bool hash[Max]; int N, Cnt, H[Max], Root; int64 Dp[Max], up[Max], down[Max][3]; void Clear() { Cnt = 0; memset(H, 0, sizeof(H)); memset(up, 0, sizeof(up)); memset(down, 0, sizeof(down)); } int64 Treedp_Dp(int i) { if (Dp[i] != -1) return Dp[i]; int64 t1 = MAX, t2 = 0; bool flag = false; for (int j = H[i], v; j; j = E[j].next) { v = E[j].v; if (!hash[v]) hash[v] = flag = true; else continue; t1 = min(Treedp_Dp(v), E[j].w), t2 = max(t2, t1); } if (!flag) return MAX; Dp[i] = t2; return t2; } void Treedp() { memset(Dp, -1, sizeof(Dp)); memset(hash, 0, sizeof(hash)); hash[Root] = true; printf("%lld\n", Treedp_Dp(Root)); } void Center_find() { int64 t1 = 0, t2 = MAX; for (int i = 1; i <= N; ++i) { t1 = max(up[i], down[i][1]); if (t1 < t2) t2 = t1, Root = i; } } void Center_upFind(int u, int fa, int64 dis) { if (u != fa) { up[u] = up[fa] + dis; int64 tmp = 0; if (down[fa][1] == down[u][1] + dis) tmp = down[fa][2] + dis; else tmp = down[fa][1] + dis; if (tmp > up[u]) up[u] = tmp; } for (int j = H[u], v; j; j = E[j].next) { v = E[j].v; if (hash[v]) continue; hash[v] = true; Center_upFind(v, u, E[j].c); } } void Center_downFind(int u) { for (int j = H[u], v; j; j = E[j].next) { v = E[j].v; if (hash[v]) continue; hash[v] = true; Center_downFind(v); if (down[v][1] + E[j].c > down[u][1]) { down[u][2] = down[u][1]; down[u][1] = down[v][1] + E[j].c; } else if (down[v][1] + E[j].c > down[u][2]) down[u][2] = down[v][1] + E[j].c; } } void Center() { memset(hash, 0, sizeof(hash)); hash[1] = true; Center_downFind(1); memset(hash, 0, sizeof(hash)); hash[1] = true; Center_upFind(1, 1, 0); Center_find(); } inline void edgeAdd(int &x, int &y, int &c, int &w) { E[++ Cnt].next = H[x], H[x] = Cnt, E[Cnt].v = y, E[Cnt].c = c, E[Cnt].w = w; } void Init() { for (int i = 1, x, y, c, w; i <= N - 1; ++i) { scanf("%d%d%d%d", &x, &y, &c, &w); edgeAdd(x, y, c, w); edgeAdd(y, x, c, w); } } int main() { #ifdef FILE_IO //freopen("test.in", "r", stdin); #endif // FILE_IO while (scanf("%d", &N) != EOF) { Init(); Center(); Treedp(); Clear(); } return 0; }
相关文章推荐
- zoj 3626 Treasure Hunt I (树形dp)
- ZOJ 3949 Edge to the Root(树形DP)
- (树形DP) zoj 3201
- ZOJ 1134 Strategic Game(树形DP)
- ZOJ 3824 Fiber-optic Network 树形dp 2014牡丹江现场赛F
- ZOJ 3527 树形DP(章鱼图DP)
- ZOJ 3626 Treasure Hunt I (树形dp)
- ZOJ - 3201 Tree of Tree 树形DP
- zoj 3626 树形dp
- zoj 3201 简单树形dp Tree of Tree
- ZOJ 4007 Machine Learning on a Tree [树形dp]
- ZOJ 3723 (浙大月赛)状压DP
- ZOJ - 4007 (树形dp)
- (树形DP) zoj 3626
- zoj 3527 Shinryaku! Kero Musume (树形dp---带尾巴的环的处理)
- ZOJ-3201 Tree of Tree 树形DP
- ZOJ 3201 Tree of Tree(树形DP)
- ZOJ 3201 Tree of Tree 树形DP
- ZOJ 3188 ZOJ 3188 Treeland Exhibition(树形DP)
- ZOJ 3626 Treasure Hunt I / 树形DP