Multihedgehog (模拟)

 

题意:

1-刺猬图满足:

是一棵树
    存在一个中心节点u与其它所有点相连
    每个中心节点,至少与3个节点相连
2-刺猬图满足:

是一棵树
    存在一个中心节点u与其它所有1-刺猬图的中心节点相连
    这个中心节点至少连接3个以上的1-刺猬图
    k-刺猬图依次类推,给你一棵树,问你它是不是k-刺猬图!

给定 两个数n,k

n-1行构成一个树

 

题解:

就按照题意模拟一遍就好了,把最外层的度为1的点一层层的删去。看只剩下一个节点的时候是否是在第k层

然后在模拟的过程中把构不成的情况删掉

1. 因为 节点数=k^3(差不多) 所以k>12 输出No即可 每个中心节点都要至少有3个节点相连

2. 对于一个完整的k刺猬数多延伸出来一部分(1-刺猬数),正常完整的k刺猬数他的下一层节点数不会为1,如果为1那么说明,这个刺猬数的分支是多出来,因为把当前的中心节点度数清为1才会进入下一层,所以如果进入某一层他的度数为1那么它一定不是刺猬数

我当时以为这个会在第三个判断中排除掉,死在cf第122个示例中,(一共124个,,,)

为啥会排除不了,因为flag把他标记了,就不会排除了

3. 每次删除一层度为1的节点,这一层度为1的节点的中心节点的度要>=3

4 如果最后只剩下一个节点并且当前的层数为k则该图是k-刺猬数 否则不是

5 最后的判断是 节点数太多 k太小 也就是说他可以构成的k1-刺猬数中的k1>k

第二次更新

对于上面的第二和第三个条件可以合2为1 只要把第3个条件判断的flag去掉即可

 

附赠第 122个示例

Input

21 2
3 1
4 1
5 1
6 2
7 2
8 2
1 2
9 1
9 10
9 11
9 12
10 13
10 14
10 15
11 16
11 17
11 18
12 19
12 20
12 21

Outout

No

   

#include<bits/stdc++.h>
using namespace std;
vector<int> G[100005];
int in[100005][16];
int flag[100005];///标记的点表示删除的点
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
        in[u][0]++;
        in[v][0]++;
    }
    if(k>12 || n<=3)printf("No\n");///k>12 节点数没那么多 节点数要 3^k
    else
    {
        int sum=n;///记录节点数
        for(int i=1;i<=k;i++)///枚举层数 注意下标
        {
            for(int j=1;j<=n;j++)///枚举节点
            {
                if(in[j][i-1]==1)///在当前层数中找到度为1的节点
                {
                    for(int k=0;k<G[j].size();k++)
                    {
                        int v=G[j][k];
                        if(flag[v])continue;///因为是无向图所以标记的点已经删除的点

                        if(in[v][i-1]==1)///这表示k刺猬数多延伸出来的部分 
                        {
                            //printf("%d\n",v);
                            printf("No\n");
                            return 0;
                        }

                        in[v][i]++;///记录节点在下一层的度
                    }
                    flag[j]=1;///标记的点表示当前最外层的可删除的点(度为1的点)
                    sum--;///找到度为1的节点删掉
                }
            }
            for(int j=1;j<=n;j++)
            {
                if(!in[j][i])continue;
                if(!flag[j] && in[j][i]<=2)///当前存在的点他的度都要>=3
                {
                    printf("No\n");
                    return 0;
                }
                in[j][i]=1;///把最外层度为1的节点删掉,原来的中心节点赋值为1
            }
            if(sum==1)///只剩下最后一个点了即中心节点
            {
                if(i==k)printf("Yes\n");///当前层数是第k层
                else printf("No\n");
                return 0;
            }
        }
        printf("No\n");///此情况为 节点数太多,而k太小 即sum!=1
    }
    return 0;
}

   更新过后的代码

#include<bits/stdc++.h>
using namespace std;
vector<int> G[100005];
int in[100005][16];
int flag[100005];///标记的点表示删除的点
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
        in[u][0]++;
        in[v][0]++;
    }
    if(k>12 || n<=3)printf("No\n");///k>12 节点数没那么多 节点数要 3^k
    else
    {
        int sum=n;///记录节点数
        for(int i=1;i<=k;i++)///枚举层数 注意下标
        {
            for(int j=1;j<=n;j++)///枚举节点
            {
                if(in[j][i-1]==1)///在当前层数中找到度为1的节点
                {
                    for(int k=0;k<G[j].size();k++)
                    {
                        int v=G[j][k];
                        if(flag[v])continue;///因为是无向图所以标记的点已经删除的点
                        in[v][i]++;///记录节点在下一层的度
                    }
                    flag[j]=1;///标记的点表示当前最外层的可删除的点(度为1的点)
                    sum--;///找到度为1的节点删掉
                }
            }
            for(int j=1;j<=n;j++)
            {
                if(!in[j][i])continue;
                if(in[j][i]<=2)///当前存在的点他的度都要>=3
                {
                    printf("No\n");
                    return 0;
                }
                in[j][i]=1;///把最外层度为1的节点删掉,原来的中心节点赋值为1
            }
            if(sum==1)///只剩下最后一个点了即中心节点
            {
                if(i==k)printf("Yes\n");///当前层数是第k层
                else printf("No\n");
                return 0;
            }
        }
        printf("No\n");///此情况为 节点数太多,而k太小 即sum!=1
    }
    return 0;
}

看了一下大佬的代码感觉智商被歧视了

思路

用两个set,一个存度为0的点,一个存与度为1唯一相连的点,记录与度为1相连的点的度,并删除度为1的点,循环判断一下是否存在度<3的点,若存在则输出No,当度为1的点删除完了,那么原来与度为1的点相连的点就变成了度为1的点,swap交换一下即可 输出Yes的条件是 当为k层时恰好有n个结点则为k-刺猬数

这里需要注意set的用法

在遍历set的时候需要用到迭代器

set<int>::iterator it,it2;

 

#include<cstdio>
#include<set>
#include<iostream>
using namespace std;
set<int>::iterator it,it2;
const int maxn=1e5+10;
set<int>s[maxn],t,v; 
int cnt[maxn];
int main(){
	int n,k,x,y;
	cin>>n>>k;
	for(int i=1;i<n;i++)
	{
		cin>>x>>y;
		s[x].insert(y);
		s[y].insert(x);
	}
	for(int i=1;i<=n;i++)
	if(s[i].size()==1)
	v.insert(i);
	while(n>1)
	{
		t.clear();
		for(it=v.begin();it!=v.end();it++)
		{
			it2=s[*it].begin();
			cnt[*it2]++;
			t.insert(*it2);
			s[*it2].erase(*it);
			n--;
		}
		for(it=t.begin();it!=t.end();it++)
		{
			if(cnt[*it]<3)
			{
				cout<<"No";
				return 0;
			}
			cnt[*it]=0;
		}
		swap(t,v);
		k--;
	}
	if(k==0)cout<<"Yes";
	else cout<<"No";
}

根据大佬的代码改的代码,仅仅是修改了遍历set的部分,大佬用的是set<int>::iterator it,it2;

我用的auto 不过需要注意将迭代器中内容取出来加*

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
set<int>s[maxn],v,t;
int cnt[maxn];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        s[u].insert(v);
        s[v].insert(u);
    }
    for(int i=1;i<=n;i++)if(s[i].size()==1)v.insert(i);///查找度为1的点
    while(n>1)
    {
        t.clear();
        for(auto i : v)///遍历度为1的点找与其唯一连接的点
        {
            int x=*s[i].begin();///迭代器类似于指针 加*取内容
            cnt[x]++;
            t.insert(x);
            s[x].erase(i);
            n--;
        }
        for(auto i : t)
        {
            if(cnt[i]<3)
            {
                printf("No\n");
                return 0;
            }
            cnt[i]=0;
        }
        swap(v,t);
        k--;
    }
    if(k==0)printf("Yes\n");/// 当为k层时恰好有n个结点则为k-刺猬数
    else printf("No\n");
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值