链接:点击打开链接
题意:给出一个树上每个节点的权值和是否有陷阱,最多能遇到m个陷阱,当遇到第m个陷阱时必须停下来,求获得的最大权值使多少
代码:
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
vector<int> G[50005];
int n,m,ans;
int dp[50005][5][2];
int val[50005],vis[50005],sign[50005];
void dfs(int s){
int i,j,k,tmp;
vis[s]=1;
dp[s][sign[s]][0]=dp[s][sign[s]][1]=val[s];
for(i=0;i<G[s].size();i++){
tmp=G[s][i];
if(vis[tmp])
continue;
dfs(tmp);
for(j=0;j<=m;j++){ //相当于在这个节点之前的链和这个节点结合
for(k=0;k+j<=m;k++){
if(j!=m)
ans=max(ans,dp[s][j][0]+dp[tmp][k][1]);
if(k!=m)
ans=max(ans,dp[s][j][1]+dp[tmp][k][0]);
if(j+k<m) //全用向上走的话可能走的陷阱数已经到m了却依然再走
ans=max(ans,dp[s][j][0]+dp[tmp][k][0]);
if(j+k<=m)
ans=max(ans,dp[s][j][1]+dp[tmp][k][1]);
}
}
for(j=0;j+sign[s]<=m;j++) //在用这个节点更新,避免了父节点向下和子节点向上是一条链
dp[s][j+sign[s]][0]=max(dp[s][j+sign[s]][0],dp[tmp][j][0]+val[s]);
for(j=1;j+sign[s]<=m;j++)
dp[s][j+sign[s]][1]=max(dp[s][j+sign[s]][1],dp[tmp][j][1]+val[s]);
}
}
int main(){
int i,t,u,v;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
G[i].clear();
for(i=1;i<=n;i++)
scanf("%d%d",&val[i],&sign[i]);
for(i=1;i<n;i++){
scanf("%d%d",&u,&v);
u++,v++;
G[u].push_back(v);
G[v].push_back(u);
}
ans=0;
dfs(1);
printf("%d\n",ans);
}
return 0;
}