离散数学实验2 关联矩阵、相邻矩阵、生成树、环路空间、断集空间的求解 C++

离散数学实验报告2

一、实验题目

实验题目:关联矩阵、相邻矩阵、生成树、环路空间、断集空间的求解

实验时间: 2021.12.16

二、实验目的

  1. 掌握无向连通图生成树的求解方法;

  2. 掌握基本回路系统和环路空间的求解方法;

  3. 掌握基本割集系统和断集空间的求解方法;

  4. 了解生成树、环路空间和断集空间的实际应用。

三、实验要求

  1. 给定无向简单连通图的相邻矩阵 例如:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPyNdYqm-1654332805884)(/Users/a26012/Desktop/截屏2021-12-23 15.02.35.png)]。
  2. 输出此图的关联矩阵M
  3. 求此图所有生成树个数。
  4. 输出其中任意一颗生成树的相邻矩阵(默认第i行对应顶点vi)和关联矩阵(默认第i行对应顶点vi,第j列对应边ej)。
  5. 求此生成树对应的基本回路系统(输出形式如:{e1e4e3,e2e5e3})。
  6. 求此生成树对应的环路空间(输出形式如:{Φ,e1e4e3,e2e5e3,e1e4e5e2})。
  7. 求此生成树对应的基本割集系统(输出形式如:{{e1,e4},{e2,e5},{e3,e4,e5}})。
  8. 求此生成树对应的断集空间(输出形式如:{Φ, {e1,e4}, {e2,e5}, {e3,e4,e5}, {e1,e2,e4,e5}, {e1,e3,e5}, {e2,e3,e4}, {e1,e2,e3}})。

四、实验步骤和内容

需求分析:

给定相邻矩阵,求关联矩阵,生成树个数,输出其中任意一颗生成树的相邻矩阵和关联矩阵。

求此生成树对应的基本回路系统,环路空间

求此生成树对应的基本割集系统,断集空间

输入形式与输入范围

预设输入点范围 : 0 < n < 999 0<n<999 0<n<999

邻接矩阵的边数 0 < m < 99 9 2 0<m<999^2 0<m<9992

输入形式: 相邻矩阵 如:

0 1 1 0 1
1 0 1 0 1
1 1 0 1 0
0 0 1 0 1
1 1 0 1 0

输出

示例:

0 1 1 0 1
1 0 1 0 1
1 1 0 1 0
0 0 1 0 1
1 1 0 1 0

  e1 e2 e3 e4 e5 e6 e7 
v1 1  1  1  0  0  0  0  
v2 1  0  0  1  1  0  0  
v3 0  1  0  1  0  1  0  
v4 0  0  0  0  0  1  1  
v5 0  0  1  0  1  0  1  

生成树的个数为:24

它的一棵树为:
   V1 V2 V3 V4 V5 
V1  0  1  1  0  1 
V2  1  0  0  0  0 
V3  1  0  0  1  0 
V4  0  0  1  0  0 
V5  1  0  0  0  0 

  e1 e2 e3 e4 
v1 1  1  1  0  
v2 1  0  0  0  
v3 0  1  0  1  
v4 0  0  0  1  
v5 0  0  1  0  

基本回路系统:{e4e2e1, e5e3e1, e7e3e2e6, }
环路空间:{ Φ,e1e2e4,e1e3e5,e2e3e6e7,e2e3e4e5,e1e3e4e6e7,e1e2e5e6e7,e4e5e6e7,}

基本割集系统:{e4e5e1,e4e5e7e2,e4e5e7e3,e4e5e7e6,}
断集空间{ Φ,e1e4e5,e2e4e5e7,e3e4e5e7,e4e5e6e7,e1e2e7,e1e3e7,e1e6e7,e2e3,e2e6,e3e6,e1e2e3e4e5,e1e2e4e5e6,e1e3e4e5e6,e2e3e4e5e6e7,e1e2e3e6e7,}

概要设计:

使用的数据结构与算法:

关联矩阵、相邻矩阵、广度优先遍历、深度优先遍历、矩阵树定理(Matrix-Tree 定理)求生成树个数、分治思想

程序流程:
  1. 读入相邻矩阵
  2. 根据相邻矩阵,求出邻接矩阵sq2,基尔霍夫矩阵K。
  3. 输出邻接矩阵
  4. 根据基尔霍夫矩阵和矩阵树定理求出生成树个数gauss( )。
  5. printTree( )函数中用广度优先遍历求出生成树,xl为树的相邻矩阵 ,gl为树的邻接矩阵
  6. 求基本回路系统和环路空间printSystem()。求基本回路系统方法:枚举每一条弦,如果把它加到树中,就会有且只有一条回路,该回路就是一条基本回路。求环路空间方法,深度优先搜索,枚举所有情况,进行对称差运算。
  7. 求基本割集系统,断集空间printSystem2()。求基本割集系统:枚举每一条树枝,找到该树枝对应的边割集,该割集就是一个基本割集。求断集空间方法,同上,深度优先搜索,枚举所有情况,进行对称差运算。

详细代码

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <vector>
#include <queue>
using namespace std;
int sq[1000][1000];    //相邻矩阵
int sq2[1000][10000],edx=0,eedx=0;   //邻接矩阵
int edge[1000][1000];    //边编号
int c[1000][1000];
int xl[1000][1000];    //树的相邻矩阵
int gl[1000][1000];   //树的邻接矩阵
bool st[1000];     //是否遍历到
int wsz[1000];  //方便计算对称差
int K[1000][1000];  //生成树个数
vector<vector<int>> baseC;   //基本回路系统
vector<vector<int>> baseG;   //基本割集系统
int sz=0;
const int MOD = 0x3f3f3f3f;
int gauss(int n) {//求矩阵K的n-1阶顺序主子式
    int res = 1;
    for (int i = 1; i <= n - 1; i++) {//枚举主对角线上第i个元素
        for (int j = i + 1; j <= n - 1; j++) {//枚举剩下的行
            while (K[j][i]) {//辗转相除
                int t = K[i][i] / K[j][i];
                for (int k = i; k <= n - 1; k++)//转为倒三角
                    K[i][k] = (K[i][k] - t * K[j][k] + MOD) % MOD;
                swap(K[i], K[j]);//交换i、j两行
                res = -res;//取负
            }
        }
        res = (res * K[i][i]) % MOD;
    }
    return (res + MOD) % MOD;
}


void print_sq(){
    cout<<"  ";
    for(int i=1;i<=edx;i++){
        cout<<"e"<<i<<" ";
    }
    cout<<endl;
    for(int i=1;i<=sz;i++){
        cout<<"v"<<i<<" ";
        for(int j=1;j<=edx;j++){
            if(sq2[i][j]) cout<<1;
            else cout<<0;
            cout<<"  ";
        }
        cout<<endl;
    }
}

void printTree(){
    bool st[1000];

    memset(xl,0,sizeof xl);
    memset(st,0,sizeof st);
    memset(gl,0,sizeof gl);
    queue<int> Q;
    Q.push(1);
    st[1]= true;
    while(!Q.empty()){
        int nw=Q.front();
        Q.pop();
        for(int i=1;i<=sz;i++){
            if(!st[i]&&sq[nw][i]){
                xl[nw][i]=xl[i][nw]=1;
                Q.push(i);
                st[i]= true;
            }
        }
    }

    cout<<"\n它的一棵树为:\n";
    printf("   ");
    for(int i=1;i<=sz;i++){
        printf("V%d ",i);
    }
    cout<<endl;
    for(int i=1;i<=sz;i++){
        printf("V%d ",i);
        for(int j=1;j<=sz;j++){
            printf(" %d ",xl[i][j]);
        }
        cout<<endl;
    }
    cout<<endl;
    edx=0;
    for(int i=1;i<=sz;i++){
        for(int j=i+1;j<=sz;j++){
            if(xl[i][j]){
                ++edx;
                gl[i][edx]=gl[j][edx]=1;
            }
        }
    }
    cout<<"  ";
    for(int i=1;i<=edx;i++){
        cout<<"e"<<i<<" ";
    }
    cout<<endl;
    for(int i=1;i<=sz;i++){
        cout<<"v"<<i<<" ";
        for(int j=1;j<=edx;j++){
            if(gl[i][j]) cout<<1;
            else cout<<0;
            cout<<"  ";
        }
        cout<<endl;
    }
}
void bfs(int x,int y){
    queue<int> Q;
    vector<int> tmp;
    bool st[1000];
    int fa[1000];
    memset(fa,0,sizeof fa);
    memset(st,0,sizeof st);

    Q.push(x);
    st[x]= true;
    fa[x]=-1;
    tmp.push_back(edge[x][y]);
    while(!Q.empty()){
        int nw=Q.front();
        Q.pop();
        for(int i=1;i<=sz;i++){
            if(!st[i]&&xl[nw][i]){
                xl[nw][i]=xl[i][nw]=1;
                Q.push(i);
                fa[i]=nw;
                st[i]= true;
            }
        }
        if(st[y]) break;
    }

    int nw=y;
    while(nw!=x){
        tmp.push_back(edge[nw][fa[nw]]);
        cout<<"e"<<edge[nw][fa[nw]];
        nw=fa[nw];
    }
    baseC.push_back(tmp);
}
void dfs(int nub,int idx,int type){      //枚举对称差
    if(nub==0){
        for(int i=1;i<=eedx;i++){
            if(wsz[i]%2)
                cout<<"e"<<i;
        }
        cout<<",";
        return;
    }
    if(idx==baseC.size()&&type==1) return;
    if(idx==baseG.size()&&type!=1) return;
    if(type==1){
        for(int j=0;j< baseC[idx].size() ;j++)  wsz[ baseC[idx][j] ]++;
        dfs(nub-1,idx+1,1);    //选第idx个基本回路
        for(int j=0;j<baseC[idx].size();j++)  wsz[baseC[idx][j]]--;

        dfs(nub,idx+1,1);
    }else{
        for(int j=0;j<baseG[idx].size();j++)  wsz[baseG[idx][j]]++;
        dfs(nub-1,idx+1,2);
        for(int j=0;j<baseG[idx].size();j++)  wsz[baseG[idx][j]]--;
        dfs(nub,idx+1,2);
    }
}
void printSystem(){
    int base=0;

    cout<<"\n基本回路系统:{";
    for(int i=1;i<=sz;i++){
        for(int j=i+1;j<=sz;j++){
            if(sq[i][j]&&!xl[i][j]){
                cout<<"e"<<edge[i][j];

                bfs(i,j); //2 4 / 3 4
                cout<<", ";
                base++;
            }
        }
    }
    memset(wsz,0,sizeof wsz);
    cout<<"}\n环路空间:{ Φ,";
    for(int i=1;i<=baseC.size();i++){
        dfs(i,0,1);
    }
    cout<<"}\n";
}
void gogo(int x){
    if(st[x]) return;
    st[x]= true;
    for(int i=1;i<=sz;i++){
        if(sq[x][i]) gogo(i);
    }
}
vector<int> tmp;
bool wzy(int n){
    if(n==0){
        for(int i=0;i<=sz;i++) st[i]=0;
        gogo(1);
        for(int i=1;i<=sz;i++)
            if(!st[i]){
                baseG.push_back(tmp);
                return true;
            }
        return false;
    }
    for(int i=1;i<=sz;i++){
        for(int j=i+1;j<=sz;j++){
            if(sq[i][j]&&!xl[i][j]){
                sq[i][j]=sq[j][i]=0;
                tmp.push_back(edge[i][j]);
                bool rt=wzy(n-1);
                tmp.pop_back();
                sq[i][j]=sq[j][i]=1;
                return rt;
            }
        }
    }
}
void printSystem2(){
    int base=0;
    cout<<"\n基本割集系统:{";
    for(int i=1;i<=sz;i++){
        for(int j=i+1;j<=sz;j++){
            if(xl[i][j]){
                sq[j][i]=sq[i][j]=0;
                tmp.clear();
                for(int k=1;;k++){
                    if(wzy(k)){
                        break;
                    }
                }
                baseG[baseG.size()-1].push_back(edge[i][j]);
                sq[j][i]=sq[i][j]=1;
            }
        }
    }
    for(int i=0;i<baseG.size();i++){
        for(int j=0;j<baseG[i].size();j++){
            cout<<"e"<<baseG[i][j];
        }
        cout<<",";
    }
    cout<<"}\n断集空间{ Φ,";
    memset(wsz,0,sizeof wsz);
    for(int i=1;i<=baseG.size();i++){
        dfs(i,0,2);
    }
    cout<<"}\n";
}
int main() {

    string str;
    getline(cin,str);
    while(str!="\0"){
        stringstream ss(str);
        sz++;
        for(int j=1;!ss.eof();j++){
            ss>>sq[sz][j];
        }
        getline(cin,str);
    }
    for(int i=1;i<=sz;i++){
        for(int j=i+1;j<=sz;j++){
            if(sq[i][j]){
                ++edx;
                ++eedx;
                edge[i][j]=edge[j][i]=edx;
                sq2[i][edx]=sq2[j][edx]=1;
                K[i][i]++;
                K[j][j]++;
                K[i][j]--;
                K[j][i]--;
            }
        }
    }
    print_sq();
    cout<<endl<<"生成树的个数为:"<<gauss(sz)<<endl;
    if(!gauss(sz)) return 0;
    printTree();
    printSystem();
    printSystem2();
    return 0;
}

调试分析

调试过程中所遇到的问题及解决方法

一切正常

算法的时空分析

求邻接矩阵,基尔霍夫矩阵,求生成树 O ( n 2 ) O(n^2) O(n2)

Matrix-Tree 定理(求矩阵行列式) O ( n 4 ) O(n^4) O(n4)

基本回路系统 O ( n 3 ) O(n^3) O(n3)

基本割集系统 O ( n 4 ) O(n^4) O(n4)

求断集空间,环路空间 O ( 2 n ) O(2^n) O(2n)

五、实验结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7ioy7pe-1654332805884)(/Users/a26012/Desktop/截屏2021-12-23 15.34.55.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X0JRu0BA-1654332805885)(/Users/a26012/Desktop/截屏2021-12-23 15.35.15.png)]

六、实验总结

心得体会:

  • 对无向连通图生成树的求解方法,基本回路系统和环路空间的求解方法,基本割集系统和断集空间的求解方法有了更深的理解,了解生成树、环路空间和断集空间的实际应用。很好的锻炼了代码能力,吸收了许多教训,学到了编程中的许多知识,非常有用。
  • 可能是因为这个实验比较难,有一些同学借鉴了我的代码。
  • 3
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值