您的位置:首页 > 其它

HDOJ 4276 鬼吹灯 (树形DP)

2014-04-08 11:55 239 查看
总结

1. dp[u][k] 是恰好用完 k 时间的最大价值

2. dfs(u, pre, vmax) 是计算 dp[u][1...vmax] 的值

3. dfs 内部遍历, j 从大到小, 防止重复计算 f(j) = g(j-k)

而 k 是从小到大, 因为在 134 行, dp[j] = max(dp[j], dp[j-k]+dp'[k]) 比较特殊, k 可以等于 0. 导致 dp[j] 被重复计算

代码

/*
* source.cpp
*
*  Created on: Apr 6, 2014
*      Author: sangs
*/

#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <memory.h>
#include <queue>
#include <set>
#include <algorithm>
#include <math.h>
using namespace std;

class Road {
public:
int to, cost;
Road(int _to, int _cost):to(_to), cost(_cost) {}
Road() {
to = cost = 0;
}
bool operator <(const Road &rhs) const {
return this->cost < rhs.cost;
}
};

vector<Road> graph[1000];
int val[1000];
int dp[1000][1000];

const int INF = 0X3F3F3F3F;
int dist[1000];
int father[1000];
bool mark[1000]; // mark those nodes must pass
bool visited[1000];
/*
* calculate the shortest path from 1 to n
* as well as those nodes in shortest path
* SPFA algorithm
*/
int bfs(int n) {
queue<int> record;

memset(visited, 0, sizeof(visited));
memset(mark, 0,    sizeof(mark));
memset(dist, 0x3f, sizeof(dist));

record.push(1);
dist[1] = 0;
father[1] = -1;

while(!record.empty()) {
int thisNode = record.front();
record.pop();

for(size_t i = 0; i < graph[thisNode].size(); i ++) {
int j = graph[thisNode][i].to;
//cout << j << " " << dist[i] << " " << graph[thisNode][i].cost << endl;

if(dist[thisNode] + graph[thisNode][i].cost < dist[j]) {
dist[j] = dist[thisNode] + graph[thisNode][i].cost;
father[j] = thisNode;
record.push(j);
}
}
}

for(int i = n; i != -1; i = father[i]) {
mark[i] = 1;
}
return dist
;
}
/*
* tree_dp to calculate dp[u][1...vmax]
* dp[u][k] is the maximum income when assigned k time to node u and get back to u
* pre is u's father
*/
void tree_dp(int u, int pre, int vmax) {
dp[u][0] = val[u];

for(size_t i = 0; i < graph[u].size(); i ++) { // enum v's child

int index = graph[u][i].to;
if(index == pre) continue;
if(mark[index]) continue;

tree_dp(index, u, vmax);

int cost = graph[u][i].cost;
for(int j = vmax; j >= 0; j --) {
for(int k = 0; k <= j-2*cost; k ++) {
dp[u][j] = max(dp[u][j], dp[u][j-k-2*cost]+dp[index][k]);
}
}
}
}

int main() {
freopen("input.txt", "r", stdin);
int n, T;
while(scanf("%d%d", &n, &T) != EOF) {
for(int i = 0; i <= n+10; i ++)
graph[i].clear();

for(int i = 0; i < n-1; i ++) {
int from, to, cost;
scanf("%d%d%d", &from, &to, &cost);
graph[from].push_back(Road(to, cost));
graph[to].push_back(Road(from, cost));
}

for(int i = 1; i <= n; i ++)
scanf("%d", val+i);

int cutTime = bfs(n);
T -= cutTime;

memset(dp, 0, sizeof(dp));
dp[n+1][0] = 0;
for(int i = 1; i <= n; i ++) {
if(mark[i] == 0) continue;

tree_dp(i, n+1, T);

for(int j = T; j >= 0; j --) {
for(int k = 0; k <= j; k ++) {
//for(int k = j; k >= 0; k --) {
dp[n+1][j] = max(dp[n+1][j], dp[n+1][j-k] + dp[i][k]);
}
}
}
int res = 0;
for(int i = 0; i <= T; i ++)
res = max(res, dp[n+1][i]);
printf("%d\n", res);
}

return 0;
}


  

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: