首页 > 代码库 > POJ 1947 Rebuilding Roads(树形DP)

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 node10 {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

 

POJ 1947 Rebuilding Roads(树形DP)