hdu 4714 树+DFS

题目链接: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;
}

猜你喜欢

转载自www.cnblogs.com/6262369sss/p/10034755.html