算法——判断无向图是否含有回路

1.并查集——存疑无法实现

2.DFS——存疑无法实现

3.剪枝法

剪枝法思路:

1.如果存在环,那么环中所有节点的度是大于等于2的

2.根据图论,如果无向图弧的个数大于等于节点个数,那么图必定存在环

3.把度小于2的点全部删除,并且删除与此节点相关的弧,再统计剩下节点度小于2的点,再把这些点删除,同时删除与此节点相关的弧,直到最后,形成环的节点是不会被删除的,所以如果结束后,删除节点个数小于总结点个数,那么有环,否则无环

4.整个算法借助栈来实现,并使用一个标记数组来表示节点的被删除状态,用相邻节点的度减一来模拟与节点的弧的删除

#include<iostream>
#include<vector>
#include<cstdbool>
#include<stack>
using namespace std;
//并查集
class union_set
{
private:
    vector<int>parents;
public:
    union_set(int len);
    int find_parents(int index);
    void make_union(int index1,int index2);
};
union_set::union_set(int len)
{
    int i;
    for(i=0;i<len;i++)
        parents.push_back(i);
}
int union_set::find_parents(int index)
{
    if(index==parents[index])
        return index;
    parents[index]=find_parents(parents[index]);
    return parents[index];
}
void union_set::make_union(int index1,int index2)
{
    parents[find_parents(index1)]=find_parents(index2);
}


typedef struct ArcNode
{
    int Adjvex;
    ArcNode*next=nullptr;
    ArcNode(int x,ArcNode*p):Adjvex(x),next(p) {}
} ArcNode;
//顶点表节点
typedef struct VerNode
{
    int Vervex;
    int du;
    ArcNode*First_Edge;
    VerNode(int x,ArcNode*p,int y):Vervex(x),First_Edge(p),du(y) {}
} VerNode;
class Adjacency_List
{
private:
    vector<VerNode*>VerNode_List;
    vector<int>Visited_Mark;
    vector<int>color;//节点的颜色标记,-1代表没有访问,0代表正在访问,1代表访问结束
    int line;//弧的个数
    int node;//节点的个数
public:
    Adjacency_List() {}
    void create(const vector<int>data,const int Road_Nums);
    void output();
    void Reset_mark();
    bool Cycle_or_not();//剪枝法判断此无向图是否有环成功
    //void DFS_Cycle(bool&flag,const int u);//深度优先遍历判断无向图是否有环————存疑,无法实现
    //bool use_unionset_cycle_or_not();//使用并查集判断无向图是否有环————同样存疑,无法实现
    ~Adjacency_List();
};
void Adjacency_List::create(const vector<int>data,const int Road_Nums)
{
    line=Road_Nums;
    node=data.size();
    VerNode*Node_Pointer_temp;
    ArcNode*Arc_Pointer;
    int i,j,k,weight;
    int Data_Len=data.size();
    cout<<"请输入"<<Road_Nums<<"条弧,以及弧的权重"<<endl;
    for(i=0; i<Data_Len; i++)
    {
        Node_Pointer_temp=new VerNode(data[i],nullptr,0);
        VerNode_List.push_back(Node_Pointer_temp);
        Visited_Mark.push_back(0);
        color.push_back(-1);
    }
    for(k=0; k<Road_Nums; k++)
    {
        cout<<"请输入弧的两端节点"<<endl;
        cin>>i;
        cin>>j;
        //不用担心弧被重复计数的情况,检查函数会把他排除
        Arc_Pointer=new ArcNode(j,VerNode_List[i]->First_Edge);
        VerNode_List[i]->First_Edge=Arc_Pointer;
        VerNode_List[i]->du++;
        Arc_Pointer=new ArcNode(i,VerNode_List[j]->First_Edge);
        VerNode_List[j]->First_Edge=Arc_Pointer;
        VerNode_List[j]->du++;
    }
}
void Adjacency_List::output()
{
    ArcNode*s;
    int i;
    for(i=0; i<VerNode_List.size(); i++)
    {
        cout<<VerNode_List[i]->Vervex;
        cout<<" 当前节点的度是 "<<VerNode_List[i]->du<<" ";
        s=VerNode_List[i]->First_Edge;
        while(s!=nullptr)
        {
            cout<<"——————"<<s->Adjvex;
            s=s->next;
        }
        cout<<endl;
    }
}

void Adjacency_List::Reset_mark()
{
    int i=0;
    for(i=0; i<Visited_Mark.size(); i++)
        Visited_Mark[i]=0;
}
Adjacency_List::~Adjacency_List()
{
    ArcNode*s;
    ArcNode*q;
    int i;
    for(i=0; i<VerNode_List.size(); i++)
    {
        s=VerNode_List[i]->First_Edge;
        delete VerNode_List[i];
        while(s!=nullptr)
        {
            q=s;
            s=s->next;
            delete q;
        }
    }
}
bool Adjacency_List::Cycle_or_not()
{
    stack<int>s;
    if(line>=node)//根据图论知识,如果弧的个数大于节点的个数,那么该图一定有环
        return true;
    int i,idx,num=0;
    int k;
    ArcNode*p;
    for(i=0; i<node; i++)
    {
        if(VerNode_List[i]->du<2)//把所有的度小于2的节点入栈,因为在环中的
            s.push(i);
    }
    //由于在下列循环中,无向图中回路的几个节点无法进入栈,所以num如果小于节点数,说明有回路
    while(!s.empty())
    {
        idx=s.top();
        s.pop();
        Visited_Mark[idx]=1;//从栈中弹出一个节点,就把这个节点和他周围的弧删了,标记数组代表删除
        num++;
        for(p=VerNode_List[idx]->First_Edge; p!=nullptr; p=p->next)
        {
            k=p->Adjvex;
            cout<<k<<" ";
            VerNode_List[k]->du--;
            if(VerNode_List[k]->du<2&&Visited_Mark[k]!=1)
                s.push(k);
        }
        cout<<endl;
    }
    if(num<node)
        return true;
    return false;
}
int main()
{
    vector<int>w= {0,1,2,3,4,5,6};
    Adjacency_List AL;
    AL.create(w,6);
    AL.output();
    cout<<endl<<AL.Cycle_or_not()<<endl;
    AL.Reset_mark();//重置节点的访问状态
    //目前无法使用DFS判断回路
    //bool flag=false;
    //AL.DFS_Cycle(flag,0);
    //cout<<endl<<flag<<endl;
    //我吐了,DFS的算法判断回路和并查集算法判断回路都出现了问题
    //cout<<endl<<AL.use_unionset_cycle_or_not()<<endl;
    return 0;
}

 

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值