POJ 1848 Tree

Tree

Time Limit: 1000ms

Memory Limit: 30000KB

This problem will be judged on PKU. Original ID: 1848
64-bit integer IO format: %lld      Java class name: Main

Consider a tree with N vertices, numbered from 1 to N. Add, if it is possible, a minimum number of edges thus every vertex belongs to exactly one cycle.

Input

The input has the following structure: 

x(1) y(1) 
x(2) y(2) 
... 
x(N-1) y(n-1) 
N (3 <= N <=100) is the number of vertices. x(i) and y(i) (x(i), y(i) are integers, 1 <= x(i), y(i) <= N) represent the two vertices connected by the i-th edge.

Output

The output will contain the value -1 if the problem doesn‘t have a solution, otherwise an integer, representing the number of added edges.

Sample Input

7
1 2
1 3
3 5
3 4
5 6
5 7

Sample Output

2

Source

Romania OI 2002

解题:树形dp

本题有三种状态,分别是
dp[u][0],以u为根,所有的点都在环内
dp[u][1],以u为根,除了u外其余的都在环内
dp[u][2],以u为根,除了u和与u点相连的链(至少有两个点)外,其余的点都在环内
有四种状态转移
1、所有子节点都满足在环内,只有根节点不在环内,
dp[u][1]=min(INF,sum);(sum是所有的dp[v][0]的和)
2、有一个子节点不在环内,以该子节点有一条链,将此链连到以u为根的树上,(+1)就可以使得u的所有子节点都在环内
dp[u][0]=min(dp[u][0],sum-dp[v][0]+dp[v][2]+1);
3、有一个子节点不在环内,其余自己处理,
dp[u][2]=min(dp[u][2],sum-dp[v][0]+min(dp[v][1],dp[v][2]));
4、有两个不在环内,将这两个加一条边连起来就可使得所有都在环内
dp[u][0]=min(dp[u][0],sum-dp[v][0]-dp[k][0]+min(dp[v][1],dp[v][2])+min(dp[k][1],dp[k][2])+1);

看来别人的解释,还是很好理解的

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 using namespace std;
 6 const int INF = 10010;
 7 const int maxn = 200;
 8 vector<int>g[maxn];
 9 int dp[maxn][3];
10 void dfs(int u,int fa){
11     int sum = 0;
12     dp[u][0] = dp[u][1] = dp[u][2] = INF;
13     for(int i = g[u].size()-1; i >= 0; --i){
14         if(g[u][i] == fa) continue;
15         dfs(g[u][i],u);
16         sum += dp[g[u][i]][0];
17     }
18     dp[u][1] = sum;
19     for(int i = g[u].size()-1; i >= 0; --i){
20         if(g[u][i] == fa) continue;
21         dp[u][0] = min(dp[u][0],sum - dp[g[u][i]][0] + dp[g[u][i]][2] + 1);
22         dp[u][2] = min(dp[u][2],sum - dp[g[u][i]][0] + min(dp[g[u][i]][1],dp[g[u][i]][2]));
23         for(int j = g[u].size()-1; j >= 0; --j){
24             if(g[u][j] != g[u][i] && g[u][j] != fa)
25                 dp[u][0] = min(dp[u][0],sum - dp[g[u][i]][0] - dp[g[u][j]][0]
26                                + min(dp[g[u][i]][1],dp[g[u][i]][2]) + min(dp[g[u][j]][1],dp[g[u][j]][2]) + 1);
27         }
28     }
29 }
30 int main(){
31     int n,u,v;
32     while(~scanf("%d",&n)){
33         for(int i = 0; i < maxn; ++i) g[i].clear();
34         for(int i = 1; i < n; ++i){
35             scanf("%d%d",&u,&v);
36             g[u].push_back(v);
37             g[v].push_back(u);
38         }
39         dfs(1,-1);
40         printf("%d\n",dp[1][0] >= INF?-1:dp[1][0]);
41     }
42     return 0;
43 }

时间: 2024-10-14 22:05:57

POJ 1848 Tree的相关文章

POJ 1848 Tree 树形DP

哆啦A梦的时空隧道 题目大意: 给出一棵n个点的树,求出最少添加几条边可以使得这颗树上的每个节点都在且仅在一个环内-..(题目比较坑人,没有说清楚这个环至少是三个节点) 如果无法满足,输出-1 分析: 想了很久还是没有思路--.. 去看了一下状态是什么-.. 然后自己试着推了推DP方程--ms是对的-. f[i][0]代表以i为根的子树每个顶点都在且仅在一个环中的ans f[i][1]代表以i为根的子树除去根节点外每个顶点都在且仅在一个环中的ans f[i][2]代表以i为根的子树除去根节点以及

POJ 2255 Tree Recovery 二叉树恢复

一道和Leetcode的一道题目基本上一样的题目. 给出前序遍历和中序遍历序列,要求根据这些信息恢复一颗二叉树的原貌,然后按后序遍历序列输出. Leetcode上有给出后序和中序,恢复二叉树的. 不过其实算法都是一样的.仿佛又回到了做Leetcode题的那段岁月中了. 还有就是输入是我特别处理过的,就两个函数,大家会了的无视,不会的可以学习下. #include <stdio.h> #include <string> #include <algorithm> using

Poj 1741 Tree (树的分治)

题目链接: Poj 1741 Tree 这个题目Tle的好苦啊,原来一直是树的重心没找对,Tle好长时间,终于对了,好感动,先贴个代码. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn = 10010; 8 struct node 9 { 10 int

POJ 3723 Tree(树链剖分)

POJ 3237 Tree 题目链接 就多一个取负操作,所以线段树结点就把最大和最小值存下来,每次取负的时候,最大和最小值取负后,交换即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int N = 10005; const int INF = 0x3f3f3f3f; int dep[N],

POJ 3437 Tree Grafting(有序树转化为二叉树)

Tree Grafting Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 1834   Accepted: 795 Description Trees have many applications in computer science. Perhaps the most commonly used trees are rooted binary trees, but there are other types of r

poj 3237 Tree(树链拆分)

题目链接:poj 3237 Tree 题目大意:给定一棵树,三种操作: CHANGE i v:将i节点权值变为v NEGATE a b:将ab路径上全部节点的权值变为相反数 QUERY a b:查询ab路径上节点权值的最大值. 解题思路:树链剖分.然后用线段树维护节点权值,成端更新查询. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int max

poj 1741 Tree(树的点分治)

poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出来.接着对于每一个子树再次运算.如果不用点分治的技巧,时间复杂度可能退化成\(O(n^2)\)(链).如果对于子树重新选根,找到树的重心,就一定可以保证时间复杂度在\(O(nlogn)\)内. 具体技巧是:首先选出树的重心,将重心视为根.接着计算出每个结点的深度,以此统计答案.由于子树中可能出现重复

POJ 1741 Tree(树的点分治,入门题)

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001).Define dist(u,v)=The min distance between node u and v.Give an in

poj 3237 Tree(树链剖分,线段树)

Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with