题意:
求 the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated.
思路:
- dp[i][j]:以当前节点i为根保留j个节点的个数,注:必须保留 i 节点。
- 构造对当前根节点和子节点之间的关系。
- 去掉以节点son的子树,那就是一刀切了子树,然后剩下当前这么多节点。
dp[father][node_num] = dp[father][node_num] + 1. - 不去掉以节点son的子树,那么就是枚举以节点son子树中剩下节点个数,
dp[father][j] = dp[son][k] + dp[father][j-k];
- 去掉以节点son的子树,那就是一刀切了子树,然后剩下当前这么多节点。
- 最后还要考虑所有节点都有可能做这棵有P节点树的根,
分两种,
1. 对于一开始假定搜的根,前驱没有边,所以ans = dp[node][P]
2. 对于那些除了这个(一开始假定搜的根),前驱都有边,所以要切掉才能使得以当前节点为根,ans=dp[node][P]+1.
Code:
//#include <bits/stdc++.h>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
//#pragma comment(linker, "/STACK:102400000,102400000")
const int INF=0x3f3f3f3f;
const int N=2e2+10;
struct Edge{
int v;
int next;
}edge[N<<1];
int head[N],tol;
int n,P;
void init(){
tol=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v){
edge[tol].v=v;
edge[tol].next=head[u];
head[u]=tol++;
}
int dp[N][N];
bool vis[N];
void DFS(int u){
int v,sum=0;
dp[u][1]=0; //初始化只剩根节点为0(假设没有子树存在)
for(int i=head[u];~i;i=edge[i].next){
v=edge[i].v;
if(vis[v]) continue;
vis[v]=true;
sum++;
DFS(v);
for(int j=P;j>=1;j--){
dp[u][j]=dp[u][j]+1; //砍掉这棵子树
for(int k=1;k<j;k++) //枚举子树中剩下的节点数,因为保证每棵树根节点存在,所以k<j
dp[u][j]=min(dp[u][j],dp[v][k]+dp[u][j-k]);
}
}
}
int main(){
int u,v;
while(~scanf("%d%d",&n,&P)){
init();
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
int ans=INF,root=1;
memset(vis,false,sizeof(vis));
memset(dp,INF,sizeof(dp));
vis[root]=true;
DFS(root);
ans=dp[root][P]; //一开始假设1为根的ans
for(int j=1;j<=n;j++)
if(root!=j) //不是(那个假定根)的节点的ans
ans=min(ans,dp[j][P]+1);
printf("%d\n",ans);
}
return 0;
}