HDOJ-4276(树形DP+背包DP)

来源:互联网 发布:金山软件框架 编辑:程序博客网 时间:2024/06/09 17:21

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4276

好久没有1A过树形DP了,真是开森呢~~~

因为结构是树,所以从1到N肯定会经过最短路径,冗余的时间才能去访问别的节点(并返回最短路径上的节点!!!),因此我选择将这条必然经过的最短路径分离出来,对每个关键节点进行属性DP,再对这条关键路径进行背包DP,具体分析见代码注释。

#include <cstdio>#include <cstring>#include <queue>#include <algorithm>using namespace std;#define MAX_NODE111#define MAX_EDGE222#define MAX_TIME555/*  (1)find critial path from 1 to N, it forms an array path[],    with length being M. this can be solved by BFS.  (2)we can spend E extra time apart from those on the critial path,     so we can find out how much more we can get if we spend      0~E time on each critical nodes' subtree and return to it,      say f[i][j] means value we can get if we spend j time on     i's subtree and return to i. this is TreeDP with Backpack.  (3)now how should we spend E extra time ? this is BackpackDP.   say dp(i, j) means the max value we can get if we spend    j time on subtrees of path[i,M), then   dp(i, j) = max{f[path[i]][k] + dp(i+1, j-k)}, 0 <= k <= j*/int N, T;int value[MAX_NODE];//value of each nodestruct Edge{int to, len, next;} edge[MAX_EDGE];int cnt, pre[MAX_NODE];inline void addEdge(int x, int y, int d){edge[cnt].to = y;edge[cnt].len = d;edge[cnt].next = pre[x];pre[x] = cnt++;}int dis[MAX_NODE];//dis[i] = shortest distance from i to Nint nex[MAX_NODE];//nex[i] is i's successive node from i to Nint path[MAX_NODE], M, PV;//critial path, its length and its valuebool vis[MAX_NODE];//visited flagqueue<int> Q;//bfs queueint f[MAX_NODE][MAX_TIME];//f[i][j] = max value we can get by spending j time //on subtree of i and return to i except critical pathint g[MAX_NODE][MAX_TIME];//g[i][j] = max value we can get by spending j time//on subtrees of path[i],path[i+1],...,path[M-1]bool init(){if(2 != scanf("%d%d", &N, &T)) return false;cnt = 0;memset(pre+1, -1, N << 2);int i, x, y, d;for(i = 1; i < N; ++i){scanf("%d%d%d", &x, &y, &d);addEdge(x, y, d);addEdge(y, x, d);}for(i = 1; i <= N; ++i) scanf("%d", value + i);for(int i = 1; i <= N; ++i) memset(f[i], 0, (T+1) << 2);for(int i = 0; i < N; ++i) memset(g[i], -1, (T+1) << 2);return true;}void findPath(){memset(vis + 1, false, N);dis[N] = 0;Q.push(N);vis[N] = true;nex[N] = -1;while(!Q.empty()){int x = Q.front(); Q.pop();for(int i = pre[x]; i != -1; i = edge[i].next){int y = edge[i].to;if(vis[y]) continue;nex[y] = x;dis[y] = dis[x] + edge[i].len;vis[y] = true;Q.push(y);}}memset(vis + 1, false, N);M = PV = 0;for(int x = 1; x != -1; x = nex[x]){//printf("%d ", x);path[M++] = x;PV += value[x];vis[x] = true;}//printf("\nPath value = %d\n", PV);}void treeDP(int x, int t){//if vis[x] then x is in critical path, do not count its value hereif(!vis[x])for(int i = 0; i <= t; ++i) f[x][i] = value[x];vis[x] = true;for(int i = pre[x]; i != -1; i = edge[i].next){int y = edge[i].to, d = edge[i].len << 1;if(vis[y] || t < d) continue;treeDP(y, t - d);for(int j = t; j >= d; --j)//total timefor(int k = 0; k+d <= j; ++k)//spend k time in subtree yf[x][j] = max(f[x][j], f[x][j-d-k] + f[y][k]);}//for(int i = 0; i <= t; ++i) printf("f[%d][%d] = %d\n", x, i, f[x][i]);}int dp(int i, int t){if(i == M) return 0;if(g[i][t] != -1) return g[i][t];int ans = 0, x = path[i];for(int j = 0; j <= t; ++j){ans = max(ans, f[x][j] + dp(i+1, t-j));}//printf("g[%d][%d] = %d\n", i, t, ans);return g[i][t] = ans;}void solve(){findPath();if(dis[1] > T){puts("0");return;}int surplus = T - dis[1];for(int i = 0; i < M; ++i) treeDP(path[i], surplus);printf("%d\n", dp(0, surplus) + PV);}int main(){freopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);while(init()) solve();return 0;}

0 0
原创粉丝点击