poj 1947
来源:互联网 发布:风驰网络加速器官网 编辑:程序博客网 时间:2024/05/01 15:38
题目连接:http://poj.org/problem?id=1947
题意:
给你一颗树,问去掉一个n个节点的子树所需要删除的最少边数。
思路:可以简化处理:先求出对于每个点形成一个n个节点的树最少需要删除多少边,然后对于原树中的根,因为是它本身,所以不用+1,其他的因为还要切断与根的关系,要+1处理;
对于求以每个节点为根的树形成只有n个节点所需删除最少的边数的问题。用树状dp来做;
dp【i】【j】表示以i为根,拥有j个节点所需要删除的最少边。
方法一:
首先,认为每个节点只有其本身。那么初始化dp【i】【1】=0;
那么动态转移:
删除某个子节点的话:temp=dp【i】【j】+1;
不删除的话:dp【i】【j-k】+dp【子节点】【k】
所以:dp【i】【j】=min(temp,dp【i】【j-k】+dp【子节点】【k】);
代码:
#include<iostream>#include<cstdio>#include<cstring>#define N 0xfffffffusing namespace std;int next[240][240];int mark[240];int bb;int dp[240][240];void dfs(int aa){ for(int ii=1;ii<=next[aa][0];ii++) dfs(next[aa][ii]); dp[aa][1]=0; for(int ii=1;ii<=next[aa][0];ii++) { for(int kk=bb;kk>=1;kk--) { int temp=dp[aa][kk]+1; for(int jj=1;jj<=kk;jj++) { temp=min(temp,dp[next[aa][ii]][jj]+dp[aa][kk-jj]); //cout<<"aa = "<<aa<<' '<<"son = "<<next[aa][ii]<<' '<<"many = "<<jj+kk<<' '<<dp[aa][jj+kk]<<endl; } dp[aa][kk]=temp; } } return ;}int DP(int aa,int nn){ dfs(aa); int getmin=N; for(int ii=1;ii<=nn;ii++) { if(ii==aa)continue; getmin=min(getmin,dp[ii][bb]+1); } getmin=min(getmin,dp[aa][bb]); return getmin;}void init(int nn){ for(int ii=1;ii<=nn;ii++) { for(int jj=0;jj<=nn;jj++) dp[ii][jj]=N; next[ii][0]=0; } return ;}int main(){ int i,j,m,n; int a,b; while(scanf("%d%d",&m,&n)!=EOF) { bb=n; memset(mark,0,sizeof(mark)); init(m); for(i=1;i<m;i++) { scanf("%d%d",&a,&b); next[a][++next[a][0]]=b; mark[b]=1; } int temp; for(i=1;i<=m;i++) { if(!mark[i]) { temp=DP(i,m); break; } } printf("%d\n",temp); } return 0;}
方法二:
首先,默认每个节点有其子节点,但是,都被删除掉了。那么初始化dp【i】【1】=(子节点的个数);
动态转移方程:
dp【i】【jj+kk】=min(dp【i】【jj】+dp【子节点】【kk】-1,dp【i】【jj+kk】);
代码:
#include<iostream>#include<cstdio>#include<cstring>#define N 0xfffffffusing namespace std;int next[240][240];int mark[240];int bb;int dp[240][240];void dfs(int aa){ for(int ii=1;ii<=next[aa][0];ii++) dfs(next[aa][ii]); dp[aa][1]=next[aa][0]; for(int ii=1;ii<=next[aa][0];ii++) { for(int kk=bb-1;kk>=1;kk--) { if(dp[aa][kk]<N) for(int jj=1;jj<=bb-1;jj++) if(dp[next[aa][ii]][jj]<N) { dp[aa][jj+kk]=min(dp[aa][jj+kk],dp[next[aa][ii]][jj]+dp[aa][kk]-1); //cout<<"aa = "<<aa<<' '<<"son = "<<next[aa][ii]<<' '<<"many = "<<jj+kk<<' '<<dp[aa][jj+kk]<<endl; } } } return ;}int DP(int aa,int nn){ dfs(aa); int getmin=N; for(int ii=1;ii<=nn;ii++) { if(ii==aa)continue; getmin=min(getmin,dp[ii][bb]+1); } getmin=min(getmin,dp[aa][bb]); return getmin;}void init(int nn){ for(int ii=1;ii<=nn;ii++) { for(int jj=0;jj<=nn;jj++) dp[ii][jj]=N; next[ii][0]=0; } return ;}int main(){ int i,j,m,n; int a,b; while(scanf("%d%d",&m,&n)!=EOF) { bb=n; memset(mark,0,sizeof(mark)); init(m); for(i=1;i<m;i++) { scanf("%d%d",&a,&b); next[a][++next[a][0]]=b; mark[b]=1; } int temp; for(i=1;i<=m;i++) { if(!mark[i]) { temp=DP(i,m); break; } }//题目没有说一定是1为所给树的祖先吧 printf("%d\n",temp); } return 0;}
- poj 1947
- POJ 1947
- POJ 1947
- poj 1947
- poj 1947
- poj 1947
- poj 1947
- POJ 1947
- poj 1947
- poj-1947
- poj 1947
- POJ 1947
- POJ 1947 Rebuilding Roads
- poj 1947 Rebuilding Roads
- POJ 1947 树形背包
- poj 1947 树形dp
- POJ 1947 树形dp
- POJ 1947 Rebuilding Roads
- mysql 添加字段、删除字段、调整字段顺序
- Json工具类
- SqlServer 企业管理器中不能建表的解决方法
- 瑞萨单片机命名
- Oracle 11g Alert log 文件位置的问题
- poj 1947
- 编码与字库
- C++
- Linux rootkit的检测工具使用(chkrootkit和rootkit hunter)
- C#发送Email的方法
- jquery:淡入淡出
- git学习教程资源地址
- MSComm32控件只支持16个串口问题的解决
- 普及下SSH