离散实验(图的随机生成及欧拉路的确定)

来源:互联网 发布:爱普生l351清零软件 编辑:程序博客网 时间:2024/06/06 16:32

内容

编程随机生成n个结点的无向图并能进行(半)欧拉图的判定,若是则给出欧拉(回)路。

要求:

对给定n个结点,随机生成邻接矩阵以确定某无向简单图并进行欧拉图和半欧拉图的判定,若符合则给出至少一条欧拉回路或欧拉路。

#include<iostream>#include<cstdlib>#include<ctime>using namespace std;//创建随机无向图的邻接矩阵void Creat(int **a,int n){    srand(unsigned(time(NULL)));    for(int i=0;i<n;i++){        for(int j=0;j<n;j++)            a[i][j]=0;    }    for(int i=0;i<n;i++){        for(int j=i+1;j<n;j++)            a[i][j]=rand()%2;  //上三角生成随机0,1随机数组    }    for(int i=0;i<n;i++){        for(int j=i+1;j<n;j++)  //因为是无向图            a[j][i]=a[i][j];    //对上三角作对称    }    cout<<"随机生成的邻接矩阵为:"<<endl;    cout<<"  ";    for(int i=0;i<n;i++)        cout<<i<<"  ";    cout<<endl;    cout<<"  ";    for(int i=0;i<n;i++)        cout<<"___";    cout<<endl;    for(int i=0;i<n;i++){//输出邻接矩阵        cout<<i<<"|";        for(int j=0;j<n;j++)            cout<<a[i][j]<<"  ";        cout<<endl<<" |"<<endl;    }}//删除一条边void Delete(int u,int v,int **a,int n){    if(u<0||v<0||u>n-1||v>n-1||u==v||a[u][v]==0){        cout<<"删除失败!"<<endl;        return ;    }    a[u][v]=a[v][u]=0;}//判断一条边是否存在bool Exist(int u,int v,int **a,int n){    if(u<0||v<0||u>n-1||v>n-1||u==v||a[u][v]==0)return false;return true;}//利用深度优先遍历void DFS(int v,bool *visited,int **a,int n){    visited[v]=true;    for(int u=0;u<n;u++)        if(Exist(v,u,a,n)&&!visited[u]) DFS(u,visited,a,n);}//判断是否连通bool Con(int **a,int n,bool *visited){    DFS(0,visited,a,n);  //以0为起始点遍历所有0可以到达的顶点    for(int i=0;i<n;i++){        if(!visited[i]){    //如果存在0到达不了的边,            cout<<"该图不连通!"<<endl;  //则不连通            return false;        }    }    cout<<"该图连通"<<endl;   //否则是连通的    return true;}//判断一个点除了与源点之外是否还存在边bool ExEdge(int v,int **a,int n,int k){    for(int i=0;i<n;i++){        if(i!=k){            if(a[v][i]==1) return true;        }    }    return false;}//判断一个点除了两个奇数度节点外是否还存在边bool ExEdge1(int v,int **a,int n,int k,int k1){    for(int i=0;i<n;i++){        if(i!=k&&i!=k1)            if(a[v][i]==1) return true;    }}//度全是偶数的遍历void OutDFS2(int v,int**a,int n,int k){    if(ExEdge(v,a,n,k)){  //判断v是否存在边        cout<<v<<"  ";        for(int u=0;u<n;u++){            if(u==k){  //除去与源点的边                continue;            }            if(Exist(v,u,a,n)){                Delete(v,u,a,n);                /*for(int i=0;i<n;i++){                    for(int j=0;j<n;j++)                        cout<<a[i][j];                    cout<<endl;                }*/                OutDFS2(u,a,n,k);            }        }    }    else if(!ExEdge(v,a,n,k)&&Exist(v,k,a,n)){        cout<<v<<"  ";        Delete(v,k,a,n);        OutDFS2(k,a,n,k);    }    else        cout<<v;}void OutDFS1(int v,int **a,int n,int k,int k1){    if(ExEdge1(v,a,n,k,k1)){  //判断v除了两个奇数度节点外是否存在边        cout<<v<<"  ";        for(int u=0;u<n;u++){            if(u==k||u==k1){                continue;            }            if(Exist(v,u,a,n)){                Delete(v,u,a,n);                /*for(int i=0;i<n;i++){                    for(int j=0;j<n;j++)                        cout<<a[i][j];                    cout<<endl;                }*/                OutDFS1(u,a,n,k,k1);            }        }    }    else if(!ExEdge(v,a,n,k)&&Exist(v,k,a,n)){        cout<<v<<"  ";   //先访问开始遍历的奇数度节点        Delete(v,k,a,n);        OutDFS1(k,a,n,k,k1);    }    else if(!ExEdge(v,a,n,k1)&&Exist(v,k1,a,n)){        cout<<v<<"  ";   //再访问另一个奇数度节点        Delete(v,k1,a,n);        OutDFS1(k1,a,n,k,k1);    }    else        cout<<v;}/*//从其中一个奇数度节点的遍历bool OutDFS1(int v,int p,int **a,int n,int k){    if(v==p){  //如果是另一个奇数度节点        if(ExEdge(p,a,n,p))  //并且该节点还存在边            OutDFS2(p,a,n,p);  //则对该节点遍历欧拉回路        else{            cout<<v<<"  ";  //否则直接输出            if(ExEdge(k,a,n,k)){                return false;            }        }    }    else if(ExEdge(v,a,n,k)){  //判断v是否存在边        cout<<v<<"  ";        for(int u=0;u<n;u++){  //遍历与v有边的节点            if(u==k){  //除去源点                continue;            }            if(Exist(v,u,a,n)){                Delete(v,u,a,n);                for(int i=0;i<n;i++){                    for(int j=0;j<n;j++)                        cout<<a[i][j];                    cout<<endl;                }                OutDFS1(u,p,a,n,k);            }        }    }    else if(!ExEdge(v,a,n,k)&&Exist(v,k,a,n)){        cout<<v<<"  ";  //如果该节点除了与源点外不存在边        Delete(v,k,a,n);  //则访问源点        OutDFS1(k,p,a,n,k);    }    else        cout<<v<<"  ";  //如果不符合上面所有的if,则说明已遍历完所有节点,输出最后一个节点    return true;}//从另一个的奇数度节点开始遍历欧拉路(有问题)bool OutDFS3(int v,int p,int **a,int n,int k){    if(v==p){        if(ExEdge(p,a,n,p))            OutDFS2(p,a,n,p);        else{            cout<<v<<"  ";            if(ExEdge(k,a,n,k)){                return false;            }        }    }    else if(ExEdge(v,a,n,k)){        cout<<v<<"  ";        for(int u=00;u<n;u++){            if(u==k){                continue;            }            if(Exist(v,u,a,n)){                Delete(v,u,a,n);                OutDFS3(u,p,a,n,k);            }        }    }    else if(!ExEdge(v,a,n,k)&&Exist(v,k,a,n)){        cout<<v<<"  ";        Delete(v,k,a,n);        OutDFS3(k,p,a,n,k);    }    else        cout<<v<<"  ";    return true;}*///求每个节点的度void Deg(int **a,int n,int *deg){    for(int i=0;i<n;i++){        for(int j=0;j<n;j++){            if(Exist(i,j,a,n)) deg[i]++;        }    }}//判断是否为欧拉图或者半欧拉图int Euler(int *deg,int n){    int count=0;  //记录节点为奇数的个数    for(int i=0;i<n;i++){        if(deg[i]%2==1)            count++;    }    return count;}int main(void){    int **arr;    int n;    cout<<"请输入矩阵的维度n:";    cin>>n;    arr=new int*[n];    for(int i=0;i<n;i++)        arr[i]=new int[n];    Creat(arr,n);          //随机生成邻接矩阵    /*for(int i=0;i<n;i++){  //输入测试用例        for(int j=0;j<n;j++)            cin>>arr[i][j];    }*/    bool *visited=new bool[n];  //判断是否遍历过的数组for(int i=0;i<n;i++)visited[i]=false;    bool con=Con(arr,n,visited);   //判断是否连通    int *deg=new int[n];    for(int i=0;i<n;i++)        deg[i]=0;    Deg(arr,n,deg);     //计算各节点的度,存放在deg数组中    cout<<"该图各节点的度为:"<<endl;    for(int i=0;i<n;i++)        cout<<deg[i]<<"  ";    cout<<endl;    int **a;  //定义一个a二维数组存放arr的值    a=new int*[n];  //因为在OutDFS2中会删除arr中边    for(int i=0;i<n;i++)        a[i]=new int[n];    for(int i=0;i<n;i++){        for(int j=0;j<n;j++)            a[i][j]=arr[i][j];    }    if(con&&Euler(deg,n)==0){  //欧拉回路遍历        cout<<"该图为欧拉图!"<<endl;        int k=0;        while(k<n){            cout<<endl<<endl;            cout<<"该图以"<<k<<"为源点得到的欧拉回路所经过的节点以此为:"<<endl;            OutDFS2(k,arr,n,k);            for(int i=0;i<n;i++){  //将arr复原                for(int j=0;j<n;j++)                    arr[i][j]=a[i][j];            }            k++;        }    }    else if(con&&Euler(deg,n)==2){  //欧拉路遍历        cout<<"该图为半欧拉图!"<<endl;        int temp[2];        int k=0;        for(int i=0;i<n;i++){            if(deg[i]%2==1){                temp[k++]=i;            }        }        cout<<"其中的一条欧拉路为:"<<endl;        OutDFS1(temp[0],arr,n,temp[0],temp[1]);        //OutDFS1(temp[0],temp[1],arr,n,temp[0]);        for(int i=0;i<n;i++){  //将arr复原            for(int j=0;j<n;j++)                arr[i][j]=a[i][j];        }        cout<<endl<<"另一条欧拉路为:"<<endl;        OutDFS1(temp[1],arr,n,temp[1],temp[0]);    }    else        cout<<"该图既不是欧拉图,也不是半欧拉图!"<<endl;    delete []visited;    delete []deg;}

对欧拉回路的确定可以从任意节点出发并回到该节点,但不能做到将所有的欧拉回路写出,因为每一种走法几乎都有很多的可能。

经过大佬的帮忙,修改了之前的方法,采用了与欧拉回路相同的思路,并且可以从两个不同的奇数度节点开始遍历。之前出现错误的情况也可以实现。

注释掉的部分是之前遍历欧拉路的思路,发现会出现问题,于是从另一种方向出发,采用了与欧拉回路的相同的思路,得以完成欧拉路。

 本人第一次写博客,若是有不足之处欢迎大家提出,必有所改进。

1 0