题目:http://acm.timus.ru/problem.aspx?space=1&num=1018
题意:
有一棵苹果树,苹果树的是一棵二叉树,共N个节点,树节点编号为1~N,编号为1的节点为树根,边可理解为树的分枝,每个分支都长着若干个苹果,现在要要求减去若干个分支,保留M个分支,要求这M个分支的苹果数量最多。
分析:
简单的树形dp:
d[u][q]表示以u为根的子树保留q个树枝可以得到的最多的苹果数。
状态转移也是比较显然的:是每个子树单独选一个路线还是两条路线都选。
还看到有人用的是背包的思想,其实都一样。
(提醒自己:不过这题需要注意的怎么区别一个点的两个子结点和父结点,刚开始用了临时变量,在递归的时候被改了,调试了很久才发现问题,然后改成全局变量就好了,1A。)
代码:
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int N = 100 + 9;
int d[N][N];
vector<pii>g[N],a[N];
int dfs(int u,int f,int q)
{
int& ans=d[u][q];
if(ans>=0)return ans;
ans=0;
if(q<=0)return ans;
for(int i=0;i<g[u].size();i++){
int v=g[u][i].first;
int w=g[u][i].second;
if(v==f)continue;
a[u].push_back(g[u][i]);
for(int j=0;j<q;j++)
dfs(v,u,j);
ans=max(ans,d[v][q-1]+w);
}
if(a[u].size()>=2)
for(int j=0;j<=q-2;j++){
int t=d[a[u][0].first][j]+d[a[u][1].first][q-j-2]+a[u][0].second+a[u][1].second;
ans=max(t,ans);
}
return ans;
}
int main() {
//freopen("f.txt","r",stdin);
int n,k,u,v,w;
memset(d,-1,sizeof(d));
scanf("%d%d",&n,&k);
for(int i=0;i<n-1;i++){
scanf("%d%d%d",&u,&v,&w);
g[u].push_back(pii(v,w));
g[v].push_back(pii(u,w));
}
dfs(1,-1,k);
printf("%d\n",d[1][k]);
return 0;
}