您的位置:首页 > 其它

hdu4276树形dp

2016-03-12 15:56 218 查看
题目大意:给你一棵树,每个点有个价值,每条边有花费,给你最大的花费t,求从1到n可以得到最大的价值是多少

思路:树形dp。首先从1到n的这条路唯一且每条边走了一次,可以求出这条路的花费(也可以用最短路的spfa去求),如果比给定的花费t大,则不可到达。否则,将这条路上各边的花费置零,t-=sum。然后dp[i][j]表示节点i及其子树花费了j时可获得的最大的价值。每次计算话费是,边的花费需要乘以2.。状态转移方程为:dp[u][j] = max(dp[u][j] , dp[u][up-k]+dp[v][k]);

建图是不能建单向的,必须双向建立!!!因为这个一直wa。还有求最短路径是给出了spfa()但是这个算法置零的时候不方便,可以用judge(),因为路径唯一。。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 1000005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define INF 100000000

int n , t;
struct edge
{
int u , v , w;
int next;
}E[105*2];
int head[105];
int dp[105][505];
int val[105];
int cost[105] , per[105];
int id,sum ,flag ;

void add(int u , int v , int w)
{
E[id].u = u;
E[id].v = v;
E[id].w = w;
E[id].next = head[u];
head[u] = id++;
}
/*
void spfa()
{
mem(per , -1);
for(int i = 2 ; i <= n ; i ++) cost[i] = INF;
cost[1] = 0;
queue<int>q;
q.push(1);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = head[u] ; i >= 0 ; i = E[i].next)
{
if(cost[E[i].v] > cost[u] + E[i].w)
{
cost[E[i].v] = cost[u] + E[i].w;
per[E[i].v] = i;
q.push(E[i].v);
}
}
}
for(int i = 1 ; i <= n ; i ++) cout << per[i] << endl;
for(int i = per
; i >= 0 ; i = per[i])
{
cout << E[i].u << " " << E[i].v << " " << E[i].w << endl;
E[i].w = 0;
}
}*/
/*
bool judge(int u,int pre)///找出1~n的路径
{
if(u == n)return true;
for(int i = head[u]; i != -1 ; i = E[i].next)
{
int v = E[i].v;
if(v == pre)continue;
if(judge(v,u))
{
sum += E[i].w;
E[i].w=0;
return true;
}
}
return false;///这句话必须有,因为这一句我没写WA到死.....
}
*/

void judge(int u , int per)
{
for(int i = head[u] ; i >= 0 ; i = E[i].next )
{
if(E[i].v == per) continue;
if(E[i].v == n) {sum += E[i].w ; E[i].w = 0 ; flag = 1 ; break;}
judge(E[i].v , u);
if(flag){sum += E[i].w ;E[i].w = 0; break;}
}
}

void solve(int u , int per)
{
for(int i = head[u] ; i >= 0 ; i = E[i].next)
{
if(E[i].v == per) continue;
solve(E[i].v , u);
for(int j = t ; j >= 2 * E[i].w ; j --)
{
int up = j - 2 * E[i].w;
for(int k = 0 ; k <= up ; k ++)
{
// if(dp[u][up-k] != -1 && dp[E[i].v][k] != -1)
dp[u][j] = max(dp[u][j] , dp[u][up-k] + dp[E[i].v][k]);
}
}
}
}

int main()
{
while(scanf("%d %d" , &n , &t) != EOF)
{
mem(dp , 0);id = 0;
mem(head , -1);
int u , v , w;
for(int i = 1 ; i < n ; i ++)
{
scanf("%d %d %d" , &u , &v , &w);
//if(u > v) swap(u , v);
add(u , v  , w);
add(v , u , w);
}
for(int i = 1 ; i <= n ; i ++)
{
scanf("%d" , &val[i]);
for(int j = 0 ; j <= t ; j ++) dp[i][j] = val[i];
}
flag = sum = 0;
judge(1 , -1);
//spfa();
if(sum > t)
{
printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
continue;
}
//cout << sum << endl;
t -= sum;
solve(1 , -1);
printf("%d\n" ,  dp[1][t]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: