/* dp【s】【i】代表以s为根的剩余的为i个子节点的所需要删除最小的边数 */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 155 #define inf 0x3f3f3f3f int dp[N][N]; int b[N]; int a[N]; int root; int vis[N]; int son[N]; int n,p; //思路就是一层一层的搜下去 void dfs(int s){ dp[s][1]=0;//只剩余一个点的话 不需要删除边 int k=son[s]; while(k){ dfs(k); for(int i=p;i>0;i--){ int tmp = dp[s][i]+1;//如果删除了i节点 那么只需要+1 for (int j = 1; j < i; ++ j) { if (dp[k][i - j] + dp[s][j] < tmp)//如果不删除的话,那么要判断k的子树是否存在删除变更少的边的可能 { tmp = dp[k][i - j] + dp[s][j]; } } dp[s][i]=tmp; } k=b[k];//继续从他的兄弟 } } int main(){ while(scanf("%d%d",&n,&p)==2){ memset(dp,inf,sizeof(dp)); memset(son,0,sizeof(son)); memset(vis,0,sizeof(vis)); for(int i=1;i<n;i++){ int s, t; scanf("%d%d",&s,&t); b[t]=son[s];//他的兄弟是当前s的儿子 vis[t]=1; son[s]=t;//把它设为当前的儿子 } for(int i=1;i<=n;i++){ if(!vis[i]){ root = i; break; } } //printf("root = %d\n",root); dfs(root); int ans = dp[root][p]; for(int i=1;i<=n;i++){ if(ans>dp[i][p]+1){ ans=dp[i][p]+1; } } printf("%d\n",ans); } }
时间: 2024-11-25 15:01:14