题目链接: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;
}
思路二:可以先将该路径上的总获得值保存在ans之中,再另外开一个数组tdp,对该路径以外直接相连的点背包一次就ok啦!ans+tdp[T]为所得结果!
此种解法需要注意的是,必须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
*/