题目连接:
http://acm.hdu.edu.cn/showproblem.php?pid=4714
题目意思:
给一棵树,去掉一条边和增加一条边的花费都为1,求最小的花费,使该树变成一个环。
解题思路:
把任意一节点作为树根,dfs.
对于任何分叉超过1的节点,断开与父亲节点的连接,此时父亲节点就少了一个分叉。然后选两个分支作为两端,其它分支断开再连接共花费2,所有都做完后连到根上面.
先把所有的都连到根上面凑成直线,然后连成环。
代码:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #define eps 1e-6 #define INF 0x3fffffff #define PI acos(-1.0) #define ll __int64 #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 1010000 struct Edge { int v; struct Edge *next; }*head[Maxn<<1],edge[Maxn<<1]; int n,cnt,ans; void add(int a,int b) { edge[++cnt].v=b,edge[cnt].next=head[a]; head[a]=&edge[cnt]; } int dfs(int cur,int pa) //返回分支个数 { int res=0; struct Edge * p=head[cur]; while(p) { if(p->v!=pa) res+=dfs(p->v,cur); p=p->next; } if(res>=2) //超过两个分支,将其它分支连过来 { if(cur==1) //树根 ans+=res-2; //不用练到其它地方 else ans+=res-1; //选两个,其它的边都要断开和重新连接一次 return 0; //断开了 } else return 1; //作为一个单支 } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d",&n); cnt=0; memset(head,NULL,sizeof(head)); for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } ans=0; dfs(1,0); printf("%d ",ans*2+1); } return 0; }