题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4714
本来想直接求树的直径,再得出答案,后来发现是错的。
思路:任选一个点进行DFS,对于一棵以点u为根节点的子树来说,如果它的分支数大于1,那么我们把这颗子树从整棵树上剪下来(优先减去),同时把这颗子树的分支留下两个,其它多余的也剪掉,然后把剪下来的这些部分连接到根节点那里,从而形成一条直链,总代价就是我们减的次数+把剪下来的部分连接到根节点+把最后的直链连成环。在这里剪的次数=把剪下来的部分连接到根节点的次数,把最后的直链连成环只需要一步。
参考博客:https://blog.csdn.net/cc_again/article/details/11407157
代码:
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<cmath> #include<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 1000005 int n,m,k,t,cnt; int ans; struct node{ int v,next; }edge[maxn*2]; int head[maxn]; void add(int u,int v){ edge[++cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt; } int DFS(int u,int pre){ int num=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==pre) continue; num+=DFS(v,u); } if(num>1){//如果以点u为根节点的子树的分支数大于1 if(u==1) ans+=num-2; else ans+=num-1; return 0;//这颗子树剪断了,所以返回0 } return 1;//分支数只有一个 } int main() { scanf("%d",&t); while(t--){ scanf("%d",&n); int u,v; cnt=0; memset(head,-1,sizeof(head)); for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); add(u,v); add(v,u); } ans=0; DFS(1,-1); printf("%d\n",ans*2+1); } return 0; }