题目链接

题意 : 给你一棵树,问你至少断掉几条边能够得到有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 }
View Code

 

posted on 2014-09-04 17:26  枫、  阅读(177)  评论(0编辑  收藏  举报