Perfect Tree(图论)

15 篇文章 0 订阅

题目描述
Given a positive integer k, we define a rooted tree to be k-perfect, if and only if it meets both conditions below:
•Each node is either a leaf node or having exactly k direct offsprings.
•All leaf nodes have the same distance to the root (i.e., all leaf nodes are of the same depth).
Now you are given an unrooted tree, and you should answer these questions:
•Is it possible to assign it a root, so that the tree becomes k-perfect for some positive integer k?
•If possible, what is the minimal k?

输入
Read from the standard input.
Each input contains multiple test cases.
The first line contains a single positive integer T, indicating the number of test cases.
For each test case, its first line contains a positive integer n, describing the number of tree nodes. Each of the next n − 1 lines contains two space-separated integers u and v, which means there exists an edge between node u and v on the tree.
It is guaranteed each test case gives a valid unrooted tree, and the nodes are numbered with consecutive integers from 1 to n.
The sum of n in each input will not exceed 106.

输出
Write to the standard output.
For each test case, output a single integer in a line:
•If the answer to the first question is “No”, output −1.
•Otherwise, output the minimal k.

样例输入
2
7
1 4
4 5
3 1
2 3
7 3
4 6
7
1 4
1 5
1 2
5 3
5 6
5 7

样例输出
2
-1

思路
找树的根节点,从根节点向叶节点推,确认每个节点的子节点是否为k个,叶节点的深度是否相同,注意n=1时答案为1,初始化图时不要用memset。

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>

using namespace std;
const int N=1000005;
typedef long long ll;
struct node
{
    int to,index;
}g[N<<1];
int n;
int head[N<<1],cnt,deg[N];
int dep[N];

inline void add(int u,int v)
{
    g[++cnt].to=v;
    g[cnt].index=head[u];
    head[u]=cnt;
    g[++cnt].to=u;
    g[cnt].index=head[v];
    head[v]=cnt;
}

void dfs(int u,int nxt,int d)
{
    dep[u]=d;
    for(int i=head[u];i;i=g[i].index)
    {
        int v=g[i].to;
        if(v==nxt) continue;
        dfs(v,u,d+1);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<=n;i++) head[i]=deg[i]=0;
        cnt=0;
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            deg[u]++;deg[v]++;
        }
        if(n<=3)
        {
            puts("1");
            continue;
        }
        int maxl=0;
        bool flag=false;
        for(int i=1;i<=n;i++)
        {
            if(deg[i]==n-1)
            {
                printf("%d\n",deg[i]);
                flag=true;
                break;
            }
            maxl=max(maxl,deg[i]);
        }
        if(flag) continue;
        int k=maxl-1,rt;
        for(int i=1;i<=n;i++)
        {
            if(deg[i]==k)
            {
                flag=true;
                rt=i;
                break;
            }
        }
        if(!flag)
        {
            puts("-1");
            continue;
        }
        flag=false;
        dfs(rt,-1,0);
        int mosd=-1;
        for(int i=1;i<=n;i++)
        {
            if(i!=rt)
            {
                if(deg[i]==1)
                {
                    if(mosd==-1) mosd=dep[i];
                    else if(mosd!=dep[i])
                    {
                        flag=true;
                        break;
                    }
                }
                else
                {
                    if(deg[i]!=k+1)
                    {
                        flag=true;
                        break;
                    }
                }
            }
            else
            {
                if(deg[i]!=k)
                {
                    flag=true;
                    break;
                }
            }
        }
        if(flag) puts("-1");
        else printf("%d\n",k);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值