POJ 1947 Rebuilding Roads(树形DP)

题目链接

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

 

你可能感兴趣的:(Build)