POJ 1947 Rebuilding Roads 树形dp
2012-04-04 11:16
351 查看
http://poj.org/problem?id=1947
题意:给你一棵有N个结点的树, 要求从树中剪掉一些边, 使得最后得到的子树恰好有P个结点。
思路:树形dp。用dp[i][j] 表示在以i为根的子树中保留下j个结点最少需要剪掉的边数。这样在求i结点的不同j值时,就是对其孩子的一次背包。dp[i][j] = MIN(dp[i][j] , dp[son[i]][k]+dp[i][j-k]);
代码:
题意:给你一棵有N个结点的树, 要求从树中剪掉一些边, 使得最后得到的子树恰好有P个结点。
思路:树形dp。用dp[i][j] 表示在以i为根的子树中保留下j个结点最少需要剪掉的边数。这样在求i结点的不同j值时,就是对其孩子的一次背包。dp[i][j] = MIN(dp[i][j] , dp[son[i]][k]+dp[i][j-k]);
代码:
/* 树形dp */ #include<stdio.h> #include<string.h> #define MIN(a,b) (a)>(b)?(b):(a) int N ,P ; bool map[160][160] ; int dp[160][160] ; bool vis[160] ; int root ,_min ; void dfs(int u){ dp[u][1] = 0 ; for(int j=2;j<=P;j++) dp[u][j] = N + 1 ; for(int v=1;v<=N;v++){ if(map[u][v] == 0) continue ; dfs(v) ; for(int j=P;j>=1;j--){ dp[u][j]++ ; //在孩子v中取0个结点,也就是说将孩子v连接的边去除,因此这里需要加1 for(int k=1;j-k>=1;k++){ dp[u][j] = MIN(dp[u][j] , dp[u][j-k]+dp[v][k] ) ; } } } } int main(){ int a ,b ; while(scanf("%d %d",&N,&P) == 2){ memset(map , 0 ,sizeof(map) ); memset(vis , 0 ,sizeof(vis) ); for(int i=1;i<N;i++){ scanf("%d %d",&a,&b); map[a][b] = 1 ; vis[b] = 1 ; } for(int i=1;i<=N;i++){ if(!vis[i]){ root = i ; } } dfs(root) ; _min = N + 1 ; for(int i=1;i<=N;i++){ if(i == root){ _min = MIN(_min ,dp[i][P]); } else{ _min = MIN(_min , dp[i][P]+1); //最后的最优子树不一定以原来的根为根 } } printf("%d\n",_min); } return 0; }
相关文章推荐
- poj 1947 Rebuilding Roads (树形dp)
- poj 1947 Rebuilding Roads(树形dp)
- POJ 1947 树形dp
- poj 1947 Rebuilding Roads ---树形DP
- poj 1947 经典树形dp
- 树形DP______Rebuilding Roads( POJ 1947 )
- [poj 1947] Rebuilding Roads 树形DP
- 【树形dp】poj 1947 Rebuilding Roads
- 树形DP——Rebuilding Roads ( POJ 1947 )
- POJ 1947 Rebuilding Roads (树形dp + 01背包)
- poj 1947 Rebuilding Roads 树形DP
- poj 1947 Rebuilding Roads 树形dp背包
- POJ 1947 Rebuilding Roads(树形DP + 01背包)
- POJ 1947 Rebuilding Roads(树形DP)
- POJ 1947 Rebuilding Roads(树形DP)
- POJ 1947 Rebuilding Roads(基础的树形dp)
- POJ 1947 Rebuilding Roads(树形DP)
- POJ-1947 Rebuilding Roads 树形DP
- POJ 1947-Rebuilding Roads-(树形DP)
- POJ_1947 Rebuilding Roads --树形DP