http://acm.hdu.edu.cn/showproblem.php?pid=6201
和那个HDU 2196 Computer(树形DP) 应该差不多的吧。。
题意:给你一颗树,边有权值,现在有本书,每个点都有这本书的价格,现在你可以选任意一点作为起点买这本书,跑去任意一点卖掉,过程中消耗路径的权值花费,问你任选起点和终点最大收益是多少
看了代码;这个dp【0】【u】表示最小的价格,然后初始是买,所以就可以打到只买一次。。不过理论上可能MLE。但是没有。。应该要每次都清空当前的S
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 200005;
typedef long long ll;
const int inf = 0x3f3f3f3f;
int f[maxn];
int pc[maxn];
int p[maxn];
int dp[2][maxn];
struct edge {
int to;
int cost;
edge(int to, int cost) :to(to), cost(cost) {}
};
struct node {
int id;
int md;
bool operator <(const node& s) const {
return md < s.md;
}
};
vector<edge> G[maxn];
vector<node> S[maxn];
void init(int n) {
for (int i = 1; i <= n; i++) {
G[i].clear();
S[i].clear();
}
memset(dp, 0, sizeof(dp));
}
void dfs(int u, int fa,int c) {
p[u] = c;
f[u] = fa;
dp[0][u] = pc[u];
for (int i = 0; i < G[u].size(); i++) {
edge e = G[u][i];
if (e.to == fa) continue;
int v = e.to;
dfs(v, u,e.cost);
node now;
now.id = v;
now.md = dp[0][v]+e.cost;
S[u].push_back(now);
}
if (S[u].empty()) return;
sort(S[u].begin(), S[u].end());
dp[0][u] = min(dp[0][u],S[u][0].md);
}
void dfs2(int u, int fa) {
dp[1][u] = pc[u];
if (fa != -1) {
if (S[fa][0].id != u) {
dp[1][u] = min(dp[1][u],min(dp[1][fa], dp[0][fa]) + p[u]);
} else {
if (S[fa].size() == 1) dp[1][u] = min(dp[1][u],dp[1][fa] + p[u]);
else dp[1][u] = min(dp[1][u],min(S[fa][1].md, dp[1][fa])+p[u]);
}
}
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].to;
if (v == fa) continue;
dfs2(v, u);
}
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
int n;
scanf("%d",&n);
init(n);
for(int i=1;i<=n;i++){
scanf("%d",&pc[i]);
}
for (int i = 2; i <= n; i++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
edge e(y,z);
G[x].push_back(e);
e.to=x;
G[y].push_back(e);
}
dfs(1, -1, 0);
dfs2(1, -1);
int ans=0;
for (int i = 1; i <= n; i++) {
int sum=min(dp[0][i],dp[1][i]);
ans=max(ans,pc[i]-sum);
}
printf("%d\n",ans);
}
return 0;
}
还看到别人的这种做法,代码又短。又好。看来状态的定义很关键。。
参考http://blog.csdn.net/cillyb/article/details/77924055
dp[u][0]表示以u为根的子树中买一本书的最大收益,dp[u][1]表示以u为根的子树中卖一本书的最大收
益。dp[u][0]+dp[u][1]即为在以u为根的子树中选两点的最大收益
心得:自己真的很少见到这样的方式。。。而且这个初始化。。。%
这样子把买和卖分开了,而且不用到父亲和儿子。。。。方式挺好的。
void dfs(int u, int pre)
{
dp[u][0] = -a[u];
dp[u][1] = a[u];
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i].v;
int w = g[u][i].w;
if(v == pre) continue;
dfs(v, u);
dp[u][0] = max(dp[u][0], dp[v][0]-w);
dp[u][1] = max(dp[u][1], dp[v][1]-w);
}
ans = max(ans, dp[u][0]+dp[u][1]);
}