CF1067B Multihedgehog 题解

这篇文章介绍了如何在不懂邻接矩阵的情况下,通过一种非常规方法处理刺猬图问题。通过模拟“拔刺”过程,检查每个点的连接情况来判断是否为刺猬图。算法包括查找每个点连接的度为1的点数量,以及逐步删除边的过程。最后,根据剩余边的数量判断是否为刺猬图。
摘要由CSDN通过智能技术生成

Multihedgehog,刺猬图。

因为我比较懒因为我这道题是我刚学图论时做的题,连邻接矩阵都不懂,所以我莫名奇妙的高出了一种非常规操作,调了进一周结果还通过了。这篇题解我就讲一个用不到邻接矩阵的方法。

题目定义一颗“刺猬图”为:对于每一个点,出度要么为 00 要么大于等于 33。但是我存图的方法有点特殊,我分别存了每一条边的左端点(u)和右端点(v),以及每一个点都连接着几条边。是的,这成了无向图,然后我调了半天,找到了可以判断是否为刺猬树的方法:模拟“拔刺”,我们一共需要“拔”k 次,每一次先记录每个点都连接着几个度为 11 的点,我们设这个值为 di​,如果这个图是个刺猬图,必须满足所有的 di​ 都要么是 00 要么大于等于 33。有一个 di​ 不满足就一定不是刺猬图。如果不满足就直接输出 No 即可,不用再往下执行,如果满足,就“拔刺”,将所有度为 11 的点连接着的边都删除。

最后拔完 k 次,再判断还剩几条边,如果没有边了,就说明这是个刺猬图,输出 Yes,否则输出 No

不懂可以看代码注释:

#include<bits/stdc++.h>
using namespace std;
struct Node{
    int u,v;//这条边连接u和v
    bool sf;//后续“拔刺”用到的,记录这根“刺”是否被“拔”了
}bian[100005];//每一条边
int dian[100005];//每一个点的度
int ci[100005];//每一个点连接着几个度为1的点
int n,k;
bool cicicici(){
    memset(ci,0,sizeof(ci));
    //找由外向内第二层的那些点,都连着几个度为1的点
    for(int i=1;i<n;i++){//分别找每条边的u和v
        if(bian[i].sf){
            //如果这个点的度为1,也就是刺猬图最外层的刺
            if(dian[bian[i].u]==1)ci[bian[i].v]++;
            if(dian[bian[i].v]==1)ci[bian[i].u]++;
        }
    }
    for(int i=1;i<=n;i++){
        if(ci[i]!=0&&ci[i]<3)return false;
        //如果有第二层的点只连了1或2个最外层的点,那么这个图就一定不是刺猬图
    }
    return true;
}
bool du(){
    memset(dian,0,sizeof(dian));
    for(int i=1;i<n;i++){//计算每个点的度
        if(bian[i].sf){
            dian[bian[i].u]++;
            dian[bian[i].v]++;
        }
    }
    return cicicici();
}
void baci(){//拔刺
    for(int i=1;i<n;i++){
        if(bian[i].sf){
            if(dian[bian[i].u]==1||dian[bian[i].v]==1){
                //如果连着度为1的点就把这条边删除
                bian[i].sf=false;
            }
        }
    }
    return;
}
int diandian(){
    int cnt=0;
    for(int i=1;i<n;i++){
        if(bian[i].sf)cnt++;//还有几条边
    }
    return cnt;
}
void no(){cout<<"No\n";exit(0);}//压行用的
void yes(){cout<<"Yes\n";exit(0);}
int main(){
    cin>>n>>k;
    if(k>12||n==1)no();//3^13>10^4
    for(int i=1;i<n;i++){
        cin>>bian[i].u>>bian[i].v;
        bian[i].sf=true;
    }
    if(!du())no();//先判断一遍
    for(int i=1;i<=k;i++){//需要拔k次刺
        baci();
        if(!du())no();
        else if(i==k&&diandian()==0)yes();
        if(diandian()==0)no();
    }
    no();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值