【POJ 1848】Tree【树形DP】
2014-08-04 21:35
302 查看
题意:给定一棵树,要添加一些边,不能是重边,不能是自环,让它的每一个结点都恰好属于一个环,求最少添加的边数。
思路:树形DP, 定义dp[i][0]表示i为根的子树所满足条件的最优解,dp[i][1]表示以i为根的子树除了i节点外的点满足条件的最优解,dp[i][2]表示以i为根的子树,除了i节点以及它的一个直接孩子节点除外的点满足条件的最优解。
转移方程:dp[i][1] = ∑dp[k][0] (k为i的孩子节点),
dp[i][2] = (∑dp[k][0])-dp[j][0]+min(dp[j][1], dp[j][2]),
dp[i][0] = min(min((∑dp[k][0])-dp[j][0]+dp[j][2]+1), min((∑dp[k][0])-dp[j][0]-dp[h][0]+min(dp[j][1], dp[j][2])+min(dp[h][1], dp[h][2]))
第一个转移方程显然成立,第二个转移方程相当于在i的孩子中找到j使得i, j不在环中,也就是对于j为根的子树中,j不在环中所需要的边数最小值,也就是min(dp[j][1], dp[j][2])。
第三个转移方程,分为两种情况,在i的孩子中找到一个j并且使得j的一个孩子与j都不在换中,然后这三个点连成环,即min((∑dp[k][0])-dp[j][0]+dp[j][2]+1), 第二种情况就是寻找i的两个孩子,使得这三个点在同一个环中,也就是后面的式子了。
思路:树形DP, 定义dp[i][0]表示i为根的子树所满足条件的最优解,dp[i][1]表示以i为根的子树除了i节点外的点满足条件的最优解,dp[i][2]表示以i为根的子树,除了i节点以及它的一个直接孩子节点除外的点满足条件的最优解。
转移方程:dp[i][1] = ∑dp[k][0] (k为i的孩子节点),
dp[i][2] = (∑dp[k][0])-dp[j][0]+min(dp[j][1], dp[j][2]),
dp[i][0] = min(min((∑dp[k][0])-dp[j][0]+dp[j][2]+1), min((∑dp[k][0])-dp[j][0]-dp[h][0]+min(dp[j][1], dp[j][2])+min(dp[h][1], dp[h][2]))
第一个转移方程显然成立,第二个转移方程相当于在i的孩子中找到j使得i, j不在环中,也就是对于j为根的子树中,j不在环中所需要的边数最小值,也就是min(dp[j][1], dp[j][2])。
第三个转移方程,分为两种情况,在i的孩子中找到一个j并且使得j的一个孩子与j都不在换中,然后这三个点连成环,即min((∑dp[k][0])-dp[j][0]+dp[j][2]+1), 第二种情况就是寻找i的两个孩子,使得这三个点在同一个环中,也就是后面的式子了。
#include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; #define N 110 #define inf 10000 vector<int>V ; int dp [3]; void dfs(int u, int f) { int i, j, v, sum = 0; vector<int>sun; for (i = 0;i < V[u].size();i++) { v = V[u][i]; if (v == f) continue; dfs(v, u); sun.push_back(v); sum += dp[v][0]; } if (sun.size() == 0) { dp[u][1] = 0, dp[u][0] = inf, dp[u][2] = inf; return; } dp[u][1] = sum; int t1, t2; t2 = t1 = inf; for (i = 0;i < sun.size();i++) { v = sun[i]; t2 = min(t2, sum-dp[v][0]+min(dp[v][1], dp[v][2])); t1 = min(t1, sum-dp[v][0]+dp[v][2]+1); for (j = i+1;j < sun.size();j++) { int vv = sun[j]; t1 = min(t1, sum-dp[v][0]-dp[vv][0]+1+min(dp[v][1],dp[v][2])+min(dp[vv][1], dp[vv][2])); } } dp[u][0] = t1, dp[u][2] = t2; } int main() { int n, i, j, u, v; while (~scanf("%d", &n)) { for (i = 1;i <= n;i++) V[i].clear(); for (i = 1;i < n;i++) { scanf("%d%d", &u, &v); V[u].push_back(v), V[v].push_back(u); } dfs(1, -1); if (dp[1][0] >= inf) puts("-1"); else printf("%d\n", dp[1][0]); } }
相关文章推荐
- poj 1848 Tree(树形DP,太难了,三种状态,四种状态转换)
- poj 1848 Tree 树形dp
- POJ 1848 Tree 树形DP
- poj 1848 Tree 树形dp
- poj 2486 Apple Tree (树形背包dp)
- POJ 1848树形DP
- pku 1848 Tree(有点麻烦的树形DP)
- POJ 1741 Tree 树形DP(分治)
- POJ 1848 树形DP
- POJ 1741 Tree 树形DP(分治)
- POJ Apple Tree 树形dp
- pku1848 Tree 树形DP
- poj 1848 树形dp(添加最少的边每点都恰在一个圈中)
- pku 树形DP 1848 Tree 解题报告
- poj 1848 树形dp
- POJ 1848 (一道不错的树形dp)
- Apple Tree POJ - 2486 树形dp
- POJ 1848 Tree
- POJ_1947 Rebuilding Roads --树形DP
- HDU3848 CC On The Tree, 树形DP