POJ-1947-树形dp+01背包

来源:互联网 发布:层次数据库 编辑:程序博客网 时间:2024/06/05 17:00

题目大意:给定一棵树,问最少删去几条边能使得有一部分被分离出来的子树的节点个树为k的;

题目解析:定义dp[i][j]为当前在第i个节点使得以他为根的子树有j的节点所删掉最少的边树,那么枚举他的所有儿子的时候,如果不要这个子树那么dp[root][j]就需要+1,否则就是个01背包了;最后如果根不是整棵树的根的时候还需要+1,因为需要把它从它的父亲节点断掉;

AC代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<string>using namespace std;const int inf=0x3fffffff;const int maxn=160;int tot,head[maxn],n,m,dp[maxn][maxn],sum[maxn];bool vis[maxn];struct Edge{        int to,next;}edge[maxn<<1];void init(){        memset(head,-1,sizeof(head));        tot=0;}void addedge(int u,int v){        edge[tot].to=v;        edge[tot].next=head[u];        head[u]=tot++;}void dfs(int root,int fa){                dp[root][1]=0;        for(int i=head[root];i!=-1;i=edge[i].next)        {                int v=edge[i].to;                if(fa==v)       continue;                dfs(v,root);                for(int j=m;j>=1;j--)                {                        int temp=dp[root][j]+1;                        for(int k=1;k<j;k++)                        {                                if(dp[root][k]>=inf||dp[v][j-k]>=inf)   continue;                                temp=min(temp,dp[root][k]+dp[v][j-k]);                        }                        dp[root][j]=temp;                }        }}int main(){        while(scanf("%d%d",&n,&m)!=EOF)        {                init();                memset(vis,0,sizeof(vis));                memset(sum,0,sizeof(sum));                for(int i=0;i<=n;i++)                        for(int j=0;j<=m;j++)                                dp[i][j]=inf;                for(int i=1;i<n;i++)                {                        int u,v;                        scanf("%d%d",&u,&v);                        addedge(u,v);                        addedge(v,u);                        vis[v]=1;                }                int root;                for(int i=1;i<=n;i++)                        if(!vis[i])                                root=i;                dfs(root,-1);                int ans=dp[root][m];                for(int i=1;i<=n;i++)                {                        ans=min(ans,dp[i][m]+1);                }                printf("%d\n",ans);        }        return 0;}




0 0