题目:
给出一棵树,现要从树的1号节点走到n号节点,每条边都需要一定的时间才能走过,并且每个节点有相应的财宝,现在给出时间t,问能不能在时间t之内走到n节点且使得所获得的财宝最多(每个节点的财宝只能收集一次)
分析:
先spfa算出1号节点走到n号节点所经过的节点,算出的最短路若不满足小于等于给定的时间t,要被饿死。在spfa中,用path数组记录每个节点的前驱以及该节点是从那条边过来的,走完之后,用n的前驱把该路上的边权全部更新为0,表示不用时间花费,再在深搜之前把总时间减掉他即为其他走过了两次的不在最短路径上面的节点所花费的时间总和。
树上背包的转移方程为
dp[x][i] = ∑max(dp[x][j]+dp[y][i-j-temp])
边为x与y,temp为当前的边权

1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 const int maxn = 205; 8 const int maxm = 1005; 9 const int inf = 1e9; 10 #define debug puts("here"); 11 12 int dp[maxn][maxm],n,m; 13 int po[maxm],tol; 14 int w[maxn]; 15 bool use[maxm]; 16 int dis[maxm],q[maxm]; 17 18 struct node{ 19 int y,next,val; 20 }edge[maxm]; 21 22 void add(int x,int y,int z){ 23 edge[++tol].y = y; 24 edge[tol].val = z; 25 edge[tol].next = po[x]; 26 po[x] = tol; 27 } 28 29 int spfa(){ 30 int h = 0,t = 0; 31 q[t++] = 1; 32 for(int i=1;i<=n;i++) 33 dis[i] = inf; 34 dis[1] = 0; 35 int path[maxm] = {0}; 36 int qq[maxm]; 37 memset(use,false,sizeof(use)); 38 while(h<t){ 39 int x = q[h++]; 40 use[x] = false; 41 for(int i=po[x];i;i=edge[i].next){ 42 int y = edge[i].y; 43 if(dis[x]+edge[i].val<dis[y]){ 44 dis[y] = dis[x]+edge[i].val; 45 path[y] = x; 46 qq[y] = i; 47 if(!use[y]){ 48 q[t++] = y; 49 use[y] = true; 50 } 51 } 52 } 53 } 54 for(int i=n;i;i=path[i]) 55 edge[qq[i]].val = 0; 56 return dis[n]; 57 } 58 59 void dfs(int x){ 60 use[x] = true; 61 for(int k=po[x];k;k=edge[k].next){ 62 int y = edge[k].y; 63 if(use[y]) 64 continue; 65 dfs(y); 66 int temp = edge[k].val*2; 67 for(int i=m;i>=temp;i--) 68 for(int j=i-temp;j>=0;j--) 69 dp[x][i] = max(dp[x][i],dp[x][j]+dp[y][i-temp-j]); 70 } 71 for(int i=0;i<=m;i++) 72 dp[x][i] += w[x]; 73 } 74 75 int main(){ 76 freopen("sum.in","r",stdin); 77 int x,y,z; 78 while(cin>>n>>m){ 79 tol = 0; 80 memset(po,0,sizeof(po)); 81 memset(dp,0,sizeof(dp)); 82 for(int i=1;i<n;i++){ 83 scanf("%d%d%d",&x,&y,&z); 84 add(x,y,z); 85 add(y,x,z); 86 } 87 for(int i=1;i<=n;i++) 88 scanf("%d",&w[i]); 89 int qq = spfa(); 90 if(qq>m){ 91 puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!"); 92 continue; 93 } 94 memset(use,false,sizeof(use)); 95 m -= qq; 96 dfs(1); 97 cout<<dp[1][m]<<endl; 98 } 99 return 0; 100 }