Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 7940 | Accepted: 3534 |
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
[A subtree with nodes (1, 2, 3, 6, 7, 8) will become isolated if roads 1-4 and 1-5 are destroyed.]
题目的意思:
给你一棵树,求通过求通过删除最少的边,使得剩余子树有给定的节点数。
d[i][j]表示以i为根的子树删除j个结点所需删除的最小边数。
需要注意的是所要求得到的剩余子树没有要求一定包括整棵树的根结点。
#include<cstdio> #include<cstring> #include<vector> using namespace std; #define Min_(a,b) (a<b?a:b) int N,P,flag,Min; int d[160][160],s[160]; //s[i]存下以i为根的子树所拥有的最多结点数 bool vis[160]; vector<int> son[160]; void DFS(int x) { int i,j,k,v; if(x==flag) s[x]=0; else s[x]=1; d[x][0]=0; for(i=0;i<son[x].size();i++) { v=son[x][i]; DFS(v); s[x]+=s[v]; for(j=N;j>=0;j--) for(k=0;k<=j;k++) { if(d[x][j-k]!=-1 && d[v][k]!=-1) { if(d[x][j]==-1) d[x][j]=d[x][j-k]+d[v][k]; else d[x][j]=Min_(d[x][j],d[x][j-k]+d[v][k]); } } } if(x!=flag) { d[x][s[x]]=1; if(s[x]>P) Min=d[x][s[x]-P]+1<Min?d[x][s[x]-P]+1:Min; else if(s[x]==P) Min=1; } } int main() { int i,u,v; while(scanf("%d%d",&N,&P)==2) { memset(vis,0,sizeof(vis)); for(i=1;i<=N;i++) son[i].clear(); for(i=1;i<N;i++) { scanf("%d%d",&u,&v); son[u].push_back(v); vis[v]=1; } memset(d,-1,sizeof(d)); Min=1000; for(i=1;i<=N;i++) { if(!vis[i]) { flag=i; //flag标记根节点 DFS(i); } } if(d[flag][N-P]<Min) Min=d[flag][N-P]; printf("%d\n",Min); } return 0; }