这周可真是大起大落,情况不断变化,突然来的放假打乱了学习的进度,欣慰的是最终还是回到了家里,几日来紧绷的心情也缓解了。这周没看新的知识,只是看了几道树形dp的题目。
二叉苹果树
题意:一棵二叉苹果树,有N个结点,编号为1-N,树根编号为1。用一根树枝两端连接的结点的编号来描述一根树枝的位置。一些树枝上长有苹果,现对树进行剪枝操作。给定保留的树枝数量,求出最多能留住多少苹果。
题解:因为题目数据量不大,这次用邻接矩阵来写。设w[x][y]为边的值,因为树是双向的,同时记录w[y][x]。设tree[v,1]为节点v的左子树,tree[v,2]为节点v的右子树,然后递归建树。下一步找状态转移方程,设f[i][j]表示以i为节点的根保留k条边的最大值,则分析可得,f[v][k]=max(f[v][k],(f[tree[v][1]][i]+f[tree[v][2]][k-i-1]+num[v]))。最后求得f[1][Q+1]即为答案。
#include<bits/stdc++.h>
using namespace std;
const int x=105;
int n,q;
int tree[x][5]={0},w[x][x]={0},num[x]={0},f[x][x]={0};
void build(int x,int y,int z);
void settree(int v)
{ int k=0;
for(int i=0;i<=n;i++)
if(w[v][i]>=0)
{ k++;
build(v,i,k);
if(k==2) return;
}
}
void build(int x,int y,int z)
{
num[y]=w[x][y];
tree[x][z]=y;
w[x][y]=-1;w[y][x]=-1;
settree(y);
}
void dfs(int v,int k)
{ if(k==0) f[v][k]=0;
else if(tree[v][1]==0 && tree[v][2]==0) f[v][k]=num[v];
else
{ f[v][k]=0;
for(int i=0;i<k;i++)
{ if(f[tree[v][1]][i]==0) dfs(tree[v][1],i);
if(f[tree[v][2]][k-i-1]==0) dfs(tree[v][2],k-i-1);
f[v][k]=max(f[v][k],(f[tree[v][1]][i]+f[tree[v][2]][k-i-1]+num[v]));
}
}
}
int main()
{ cin>>n>>q;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
{ w[i][j]=-1;
w[j][i]=-1;
}
for(int i=0;i<n;i++)
{ int x,y,z;
cin>>x>>y>>z;
w[x][y]=z;
w[y][x]=z;
}
settree(1);
dfs(1,q+1);
cout<<f[1][q+1]<<endl;
}