题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4714
题意:
给你一棵树,添加和删除一条边的代价都是1。问你将这棵树变成一个环的最小代价。
题解:
贪心。
将树变成环的过程,无非就是先拆掉k条边,将这棵树变成若干个链,然后再添加k+1条边,将所有链连成环。
所以要让最终代价最小,就是让拆的边最少。
对于节点i的子树,如果要将这棵子树全部变成链,则总共有两种情况:
(1)节点i的儿子数 <= 1,这样的话根本就不用拆啊。
(2)节点i的儿子数 >= 2:
I. 节点i的所有儿子只保留2个,其他的一律删除。
II. 将i与par[i]的边也删掉。这样的话可以减少par[i]的儿子数,使在节点par[i]时删的边尽可能少,显然更优。
最后答案为:拆掉的边 * 2 + 1
AC Code:
1 #pragma comment(linker,"/STACK:102400000,102400000") 2 #include <iostream> 3 #include <stdio.h> 4 #include <string.h> 5 #include <vector> 6 #define MAX_N 1000005 7 #define MAX_E 2000005 8 9 using namespace std; 10 11 struct Edge 12 { 13 int dst; 14 int nex; 15 }; 16 17 int n,t; 18 int ans; 19 int cnt; 20 int head[MAX_N]; 21 Edge edge[MAX_E]; 22 23 void add(int s,int t) 24 { 25 edge[cnt].dst=t; 26 edge[cnt].nex=head[s]; 27 head[s]=cnt++; 28 } 29 30 void read() 31 { 32 scanf("%d",&n); 33 memset(head,-1,sizeof(head)); 34 cnt=0; 35 int a,b; 36 for(int i=1;i<n;i++) 37 { 38 scanf("%d%d",&a,&b); 39 add(a,b); 40 add(b,a); 41 } 42 } 43 44 int dfs(int now,int p) 45 { 46 int cnt=0; 47 for(int i=head[now];i!=-1;i=edge[i].nex) 48 { 49 int temp=edge[i].dst; 50 if(temp!=p) cnt+=dfs(temp,now); 51 } 52 if(cnt>=2) 53 { 54 ans+=cnt-2+(p!=-1); 55 return 0; 56 } 57 return 1; 58 } 59 60 void work() 61 { 62 ans=0; 63 dfs(1,-1); 64 printf("%d ",ans*2+1); 65 } 66 67 int main() 68 { 69 scanf("%d",&t); 70 while(t--) 71 { 72 read(); 73 work(); 74 } 75 }