dp[s][i]:记录s结点,要得到一棵j个节点的子树去掉的最少边数 考虑其儿子k
1)如果不去掉k子树,则 dp[s][i] = min(dp[s][j]+dp[k][i-j]) 0 <= j <= i
2)如果去掉k子树,则 dp[s][i] = dp[s][i]+1 总的为 dp[s][i] = min (min(dp[s][j]+dp[k][i-j]) , dp[s][i]+1 )
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 8685 | Accepted: 3910 |
Description
Input
Output
Sample Input
11 6 1 2 1 3 1 4 1 5 2 6 2 7 2 8 4 9 4 10 4 11
Sample Output
2
Hint
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int dp[200][200],father[200],brother[200],son[200]; int n,p; void dfs(int root) { int k,i,j,temp; for(i=0;i<=p;i++) dp[root][i]=100000; dp[root][1]=0; k=son[root]; // printf("son[%d] = %d\n",root, k); while(k!=0) { dfs(k); for(i=p;i>=1;i--) { temp=dp[root][i]+1; for(j=1;j<i;j++) { temp=min(temp,dp[root][j]+dp[k][i-j]); // printf("dp=%d %d\n",dp[root][j],dp[k][i-j]); } dp[root][i]=temp; } k=brother[k]; } } int main() { int x,y,i,root,ans; while(~scanf("%d%d",&n,&p)) { memset(dp,0,sizeof(dp)); memset(father,0,sizeof(father)); memset(brother,0,sizeof(brother)); memset(son,0,sizeof(son)); for(i=0;i<n-1;i++) { cin>>x>>y; father[y]=1;//记录该点有父亲节点 brother[y]=son[x];//记录兄弟节点 son[x]=y;//记录子节点 } for(i=1;i<=n;i++) { if(father[i]==0) { root=i;//找到根节点 不一定根结点是1. break; } } dfs(root); ans=dp[root][p]; // printf("ans=%d\n",ans); for(i=1;i<=n;i++) { if(dp[i][p]+1<ans)//除了根节点,其他节点要想成为独立的跟,必先与父节点断绝关系,所以要先加1 ans=dp[i][p]+1; } cout<<ans<<endl; } return 0; }