树形dp——Tree2cycle

一、问题描述(题目链接

给你一棵树,删除或添加一条边的费用都是1,问使它变成一个环的最小费用。

二、解题思路

回溯法,然后回溯的时候的当前节点度数>2(如果是成环的话肯定就是2或者小于2)就把它和父节点之间的边砍掉。每砍掉一次,以后是要连上的,只需乘2就行。由于是回溯回来的,父节点在子节点阶段就考虑了一次,相当于与该子节点与父节点没有边了,所以父节点的度数减1。

三、代码实现

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 1000000 + 10;
 9 vector<int>G[maxn];
10 int degree[maxn],ans,n;
11 
12 void init()
13 {
14     ans = 0;
15     memset(degree, 0, sizeof(degree));
16     for (int i = 0; i <= n; i++)
17         G[i].clear();
18 }
19 
20 void dfs(int son, int fa)
21 {
22     int k = G[son].size();
23     for (int i = 0; i < k; i++)
24     {
25         int newson = G[son][i];
26         if (newson == fa)    continue;
27         dfs(newson, son);
28         if (degree[newson] > 2)
29         {
30             degree[son]--;                //父节点要减一
31             ans += (degree[newson] - 2) * 2;
32         }
33     }
34 }
35 
36 int main()
37 {
38     int T;
39     scanf("%d", &T);
40     while (T--)
41     {
42         int a, b;
43         init();
44         scanf("%d", &n);
45         for (int i = 1; i < n; i++)
46         {
47             scanf("%d%d", &a, &b);
48             degree[a]++;
49             degree[b]++;
50             G[a].push_back(b);
51             G[b].push_back(a);
52         }
53         int root = 1;
54         for (int i = 1; i <= n; i++)    //找到度数为一的节点作为根节点,开始搜索
55         {
56             if (degree[i] == 1)
57             {
58                 root = i;
59                 break;
60             }
61         }
62         dfs(root, 0);
63         printf("%d
", ans + 1);
64     }
65     return 0;
66 }
原文地址:https://www.cnblogs.com/lfri/p/9485503.html