题意:
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;
}