题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4276
题目大意:对于一个每条边有耗时len,且每个点有财富值,问从1到n点在规定的T时间内,最多能收集多少财富,如果在规定的T时间内不能到达n则输出“ **** ”;
关键状态方程:
temp = edge[i].len*2;
for(j = T; j >= temp; j--)
for(k = temp; k <= j ; k++)
dp[root][j]=max(dp[root][j],dp[root][j-k] + dp[edge[i].node][k-temp]);
解题思路一:可以先将1到n的路径全部耗时全改为0,同时将T减去该路径上的耗时总和即T-=sum!dp[1][T]即为答案!
#include<stdio.h> #include<string.h> #define MAXN 105 #define MAXT 505 int dp[MAXN][MAXT]; int head[MAXN], val[MAXN], path[MAXN], tdp[MAXT],next[MAXN], cnt, N, T,sum; struct Edge{ int len; int node; int next; }edge[MAXN*2]; void add(int a, int b, int c) { edge[cnt].node = b; edge[cnt].len = c; edge[cnt].next = head[a];head[a]=cnt++; edge[cnt].node = a; edge[cnt].len = c; edge[cnt].next = head[b];head[b]=cnt++; return ; } int max(int a, int b) { return (a>b)?a:b; } bool find(int rt,int fa) { if(rt == N )return 1; for(int i = head[rt];i != -1;i = edge[i].next) { int son = edge[i].node; if(son == fa) continue; if( find(son,rt) ) { sum += edge[i].len; edge[i].len = 0; return 1; } } return 0; } int dfs(int root, int fa) { int i,j,k, temp; for(i = 0; i <= T; i++)dp[root][i] = val[root]; for(i = head[root]; ~i; i=edge[i].next) { if(edge[i].node != fa) { dfs(edge[i].node, root); temp = edge[i].len*2; for(j = T; j >= temp; j--) for(k = temp; k <= j ; k++) dp[root][j]=max(dp[root][j],dp[root][j-k] + dp[edge[i].node][k-temp]); } } return 0; } int main() { int i, a, b, c; while(~scanf("%d%d",&N,&T)) { memset(head,-1,sizeof(head)); for(cnt =0, i = 1; i < N; i++) { scanf("%d%d%d",&a, &b, &c); add(a, b, c); } for(i = 1; i <= N; i++) scanf("%d",&val[i]); sum = 0; find(1,-1); if(sum>T) printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n"); else { //memset(dp,0,sizeof(dp)); T -= sum; dfs(1, -1); printf("%d\n",dp[1][T]); } } return 0; }
此种解法需要注意的是,必须T先将路径上的所耗时间总和减掉sum,再进行dp,否则会超时,我在这里超时了好久,囧!
这思路大复杂度和上面那个差不多!稍微弱一点点!
#include<stdio.h> #include<string.h> #define MAXN 115 #define MAXT 515 int dp[MAXN][MAXT]; int head[MAXN], val[MAXN], path[MAXN], tdp[MAXT], cnt, N, T; struct Edge{ int len; int node; int next; }edge[MAXN*2]; void add(int a, int b, int c) { edge[cnt].node = b; edge[cnt].len = c; edge[cnt].next = head[a];head[a]=cnt++; edge[cnt].node = a; edge[cnt].len = c; edge[cnt].next = head[b];head[b]=cnt++; return ; } int max(int a, int b) { return (a>b)?a:b; } int find(int root, int fa) { int i; if(root == N)return 1; for(i = head[root]; ~i; i=edge[i].next) { if(edge[i].node != fa) { if(find(edge[i].node, root)) { path[++cnt] = i; return 1; } } } return 0; } int dfs(int root, int fa) { int i,j,k, temp; for(i = 0; i <= T; i++)dp[root][i] = val[root]; for(i = head[root]; ~i; i=edge[i].next) { if(edge[i].node != fa) { dfs(edge[i].node, root); temp = edge[i].len*2; for(j = T; j >= temp; j--) for(k = temp; k <= j ; k++) dp[root][j]=max(dp[root][j],dp[root][j-k] + dp[edge[i].node][k-temp]); } } return 0; } int main() { int node,sum, ans,i,j, fa, a, b, c,temp,t,k; while(~scanf("%d%d",&N,&T)) { memset(head,-1,sizeof(head)); for(cnt =0, i = 1; i < N; i++) { scanf("%d%d%d",&a, &b, &c); add(a, b, c); } for(i = 1; i <= N; i++) scanf("%d",&val[i]); cnt = 0; find(1,-1); for(i = cnt, sum = 0, ans = val[1]; i > 0; i--) sum += edge[path[i]].len,ans +=val[edge[path[i]].node] ; if(sum>T) printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n"); else { T -= sum; dfs(1, -1); memset(tdp,0,sizeof(tdp)); path[0]=-1; for(i = cnt,node = 1,fa = -1; i > -1; i--) { for(t = head[node]; ~t; t = edge[t].next) { if((t != path[i])&&(edge[t].node!=fa)) { temp = edge[t].len * 2; for(j = T; j >= temp; j--) for(k = temp; k <= j ; k++) tdp[j]=max(tdp[j],tdp[j-k] + dp[edge[t].node][k-temp]); } } fa = node; node=edge[path[i]].node; } ans += tdp[T]; printf("%d\n",ans); } } return 0; } /* 3 3 1 3 1 3 2 1 1 2 3 7 11 1 2 2 2 3 2 2 7 3 3 4 3 7 5 1 5 6 2 1 2 3 4 5 6 7 7 11 1 2 2 2 3 2 2 7 3 3 4 3 7 5 1 5 6 2 1 2 7 4 5 6 7 2 10 1 2 4 10 10 5 10 1 2 2 2 3 2 2 5 3 3 4 3 1 2 3 4 5 1 10 10 */