POJ 1947 树形DP入门题

来源:互联网 发布:以房养老骗局 知乎 编辑:程序博客网 时间:2024/06/07 22:46

给出N个点,N-1个关系,建出树形图,问最少减去几个边能得到节点数为P的树。典型树形DP题


dp[cur][j] :记录cur结点,要得到一棵j个节点的子树去掉的最少边数


转移方程用的背包的思想

对当前树的每一个子树进行计算

砍掉此子树:   dp[cur][j]=dp[cur][j]+1;

不砍掉:           for (l=0;l<=j;l++)  dp[cur][j]=Min(dp[cur][j],dp[cur][l]+dp[next][j-l]); 枚举从该树中留l个节点其他由新进子树得到的方案的代价 dp[cur][l]+dp[next][j-l];

#include "stdio.h"#include "vector"#include "math.h"#include "string.h"int inf=0x3f3f3f3f;using namespace std;struct node{    int fa;    vector<int>child;}data[160];int dp[160][160];int p;int Min(int a,int b){    if (a<b) return a; else return b;}void dfs(int cur){    int next,i,j,l;    dp[cur][1]=0;    for (i=0;i<data[cur].child.size();i++)    {        next=data[cur].child[i];        dfs(next);        for (j=p;j>=0;j--)        {            dp[cur][j]=dp[cur][j]+1;            for (l=0;l<=j;l++)                dp[cur][j]=Min(dp[cur][j],dp[cur][l]+dp[next][j-l]);        }    }}int main(){    int n,a,b,i,root,ans;    while (scanf("%d%d",&n,&p)!=EOF)    {        memset(dp,inf,sizeof(dp));        memset(data,0,sizeof(data));        for (i=1;i<n;i++)        {            scanf("%d%d",&a,&b);            data[b].fa=a;            data[a].child.push_back(b);        }        for (i=1;i<=n;i++)            if (data[i].fa==0)            {                root=i;                break;            }        dfs(root);        ans=dp[root][p];        for (i=1;i<=n;i++)            ans=Min(ans,dp[i][p]+1);        printf("%d\n",ans);    }    return 0;}



0 0