版权声明:本文为博主原创文章,转载请说明出处。 https://blog.csdn.net/xianpingping/article/details/81981215
这道题有两种做法,但是都是树形dp+分组背包
思路1:逆向考虑。
参考:https://blog.csdn.net/shuangde800/article/details/10217167
#include<bits/stdc++.h>
using namespace std;
const int maxn=10010;
int sum,cnt;
int dp[maxn][20],head[maxn];
int n,m,k;
struct node{
int to,next,val;
}G[maxn*2];
void add(int u,int v,int val)
{
G[++cnt].to=v;
G[cnt].val=val;
G[cnt].next=head[u];
head[u]=cnt;
}
void dfs(int u,int fa){
for(int i=head[u];i!=-1;i=G[i].next){
int son=G[i].to;
int val=G[i].val;
if(son==fa)
continue;
dfs(son,u);
for(int j=k;j>=1;j--){
for(int l=1;l<=j;l++){
dp[u][j]=max(dp[u][j],dp[u][j-l]+dp[son][l]+2*val-l*val);
}
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&k)){
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
cnt=0;
sum=0;
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
sum+=z;
add(x,y,z);
add(y,x,z);
}
dfs(m,-1);
printf("%d\n",sum*2-dp[m][k]);
}
return 0;
}
思路2:正向考虑:
参考:
https://blog.csdn.net/yexiaohhjk/article/details/52862116
#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
struct node{
int v,next,val;
}G[maxn];
int head[maxn],dp[maxn][20];
int n,s,k,cnt;
void add(int u,int v,int val){
G[++cnt].v=v;
G[cnt].val=val;
G[cnt].next=head[u];
head[u]=cnt;
///cnt++;
}
void dfs(int root,int p){
int i,j,l,son;
for(i=head[root];i!=-1;i=G[i].next){
son=G[i].v;
if(son==p)
continue;
dfs(son,root);
for(j=k;j>=0;j--){
dp[root][j]+=dp[son][0]+2*G[i].val;///先将dp[son][0]放进背包,由于dp[son][0]是表示用一个机器人去走完所有子树最后又回pos来,所以花费要乘2
for(l=1;l<=j;l++){///分组背包
dp[root][j]=min(dp[root][j],dp[root][j-l]+dp[son][l]+l*G[i].val);
}
}
}
}
int main()
{
int x,y,w;
while(~scanf("%d%d%d",&n,&s,&k)){
cnt=0;
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
dfs(s,-1);
printf("%d\n",dp[s][k]);
}
return 0;
}