树形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\n", ans + 1); 64 } 65 return 0; 66 }
个性签名:时间会解决一切