题意 : 给你一棵树,问你至少断掉几条边能够得到有p个点的子树。
思路 : dp[i][j]代表的是以i为根的子树有j个节点。dp[u][i] = dp[u][j]+dp[son][i-j]-1,son是u的儿子节点。初始是将所有的儿子都断开,然后-1代表的是这个儿子我需要了,不断了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #define maxn 101 6 7 using namespace std; 8 9 struct node 10 { 11 int fa,son,next ; 12 } pp[210]; 13 int head[210],cnt,root[210],root1,dp[210][210] ; 14 int p ; 15 int so[210];//统计儿子的个数 16 void dfs(int u) 17 { 18 for(int i = 0; i <= p ; i++) 19 dp[u][i] = 999999999; 20 dp[u][1] = so[u] ; 21 for(int ii = head[u] ; ii != -1 ; ii = pp[ii].next) 22 { 23 int son = pp[ii].son ; 24 dfs(son) ; 25 for(int i = p ; i >= 0 ; i--) 26 { 27 int s = dp[u][i] ; 28 for(int j = 1 ; j < i ; j++) 29 { 30 s = min(s,dp[u][j]+dp[son][i-j]-1) ; 31 } 32 dp[u][i] = s ; 33 } 34 } 35 } 36 void addedge(int u,int v) 37 { 38 pp[cnt].fa = u ; 39 pp[cnt].son = v ; 40 pp[cnt].next = head[u] ; 41 head[u] = cnt ++ ; 42 } 43 int main() 44 { 45 int n,u,v; 46 while(~scanf("%d %d",&n,&p)) 47 { 48 cnt = 0 ; 49 memset(head,-1,sizeof(head)) ; 50 memset(root,1,sizeof(root)) ; 51 for(int i = 1 ; i < n ; i++) 52 { 53 scanf("%d %d",&u,&v) ; 54 addedge(u,v) ; 55 so[u]++; 56 root[v] = 0 ; 57 } 58 for(int i = 1 ; i <= n ; i++) 59 if(root[i]) 60 { 61 root1 = i ;//根节点 62 break ; 63 } 64 dfs(root1) ; 65 int ans = dp[root1][p] ; 66 for(int i = 1 ; i <= n ; i++) 67 ans = min(ans,dp[i][p]+1) ; 68 printf("%d\n",ans) ; 69 } 70 return 0; 71 }