在不確定圖(uncertain graph)中利用Bron-Kerbosch算法發(fā)現(xiàn)極大團(maximal clique)

參考資料:
Bron-Kerbosch算法視頻介紹
極大團算法
不確定圖上求極大團算法
不確定圖上的枚舉算法研究

不確定圖:
不確定圖就是指邊或者頂點信息中帶有不確定性的圖,這種不確定性通常是通過給邊賦予權(quán)值來量化。用一個三元組 G=(V, E, β)表示一個不確定圖,其中 β 表示邊的權(quán)值,0< β <1,代表邊存在的概率。


不確定圖

如圖所示不確定圖中,每一條邊都擁有權(quán)值,用來表示該邊在實際應(yīng)用中存在的概率,所以它是一個不確定圖。
1,圖的存儲結(jié)構(gòu)用什么好?
確定為鄰接vector存儲結(jié)構(gòu),因為vector作為STL中的類,封裝了很多函數(shù),用起來很方便。
2,運行時遇到錯誤:vector subscript out of range?
應(yīng)該是有vector沒有分配足夠的空間,但是卻用了它的下標。

我們這里是把不確定圖當確定圖(也就是普通的圖),來處理的,并沒由考慮邊上的概率。之所以是用的不確定圖,主要是因為我最近研究的是不確定圖,把不確定圖的數(shù)據(jù)結(jié)構(gòu)換成確定圖的,也是一樣的。

下邊是頭文件:

Vertex_Value.h
#pragma once
#include <iostream>
using namespace std;
//這個相當于臨接表中的邊界點
class Vertex_Value
{
public:
    Vertex_Value(void);
    ~Vertex_Value(void);
    Vertex_Value(int x, float y);

public:
    int vertex;  //鄰接表中邊結(jié)點的編號
    float val;    //結(jié)點之間的概率
};
node.h
#pragma once
#include "Vertex_Value.h"
#include <vector>
using namespace std;
//相當于頭結(jié)點
class node
{
    //public:
    //  node(void);空參的構(gòu)造方法,以及析構(gòu)函數(shù)可以不用寫,系統(tǒng)會自動實現(xiàn)
    //  ~node(void);
public:
    int vertex;    //頭節(jié)點的結(jié)點編號
    vector<Vertex_Value> vec;  //這里用vector動態(tài)數(shù)組來放邊結(jié)點,Vertex_Value表示邊結(jié)點,其中有結(jié)點編號,以及邊上的概率
};
UDG.h
#pragma once
#include "node.h"

class UDG
{
    //public:
    //  UDG(void);
    //  ~UDG(void);
public:
    int vernum, arcnum;//結(jié)點數(shù)目和邊的數(shù)目
    node *AdjVector;//是鄰接vector的形式 一個數(shù)組名字叫AdjVector,數(shù)組里面存放的是node形式的的數(shù)據(jù)
};
ReadFile.h
#pragma once
#include "UDG.h"

#define path "F:\\c++_code\\test1.txt"http://文件路徑
//讀取文件
class ReadFile
{
public:
    ReadFile(void);
    ~ReadFile(void);
    void CreateUdg(UDG &g); //讀取文件后,構(gòu)建出不確定圖出來
};
BasicFunctions.h
#pragma once
#include <vector>
#include "UDG.h"
#include "Vertex_Value.h"
using namespace std;

#define $ 0.1 //概率閾值,這里我把圖當作是確定的,所以不考慮概率。
class BasicFunctions
{
public:
    BasicFunctions(void);
    ~BasicFunctions(void);

    void Bron_Kerbosch(const UDG g);//把不確定圖作為確定圖來看待,得到所有的極大團子圖

    bool IfConnect(int u, int v, UDG g);  //判斷在圖g中,結(jié)點u和結(jié)點v是否連接

    void Enum_Deterministic(vector <int> all, vector <int> some, vector <int> none, UDG g);//用在Bron_Kerbosch算法中,枚舉圖中的極大團

    vector<int> GenerateSome(vector <int> all, vector <int> some, int v ,UDG g);//用在Enum_Deterministic中,更新其中的some集合

    vector<int> GenerateNone(vector <int> all, vector <int> none, int v, UDG g);//用在Enum_Deterministic中,更新其中的none集合

};

下面是cpp文件

Vertex_Value.cpp
#include "Vertex_Value.h"
Vertex_Value::Vertex_Value(void)
{
}

Vertex_Value::~Vertex_Value(void)
{
}
Vertex_Value::Vertex_Value(int x, float y)
{
    vertex = x;
    val = y;
}
ReadFile.cpp
#include "ReadFile.h"
#include <fstream>
#include <iostream>
using namespace std;

ReadFile::ReadFile(void)
{
}

ReadFile::~ReadFile(void)
{
}
void ReadFile::CreateUdg(UDG &g)
{
    ifstream infile(path);      //讀取path里面的文本
    cout << "開始讀入文件!" << endl;
    infile >> g.vernum >> g.arcnum;   //infile在這里就類似cin操作,cin是讀取鍵盤輸入,而infile是讀取文件輸入 >> 操作返回的是左操作數(shù),也就是給g.vernum和g.arcnum賦值了
    cout << "頂點個數(shù)和邊數(shù)為:" << endl;
    cout << g.vernum << ' ' << g.arcnum << endl;
    g.AdjVector = new node[g.vernum + 1];//0號不存結(jié)點,能儲存g.vernum個結(jié)點的數(shù)組AdjVector,g.AdjVector[0]中不存放數(shù)據(jù)
    cout << "開始讀入邊,建立鄰接vector!" << endl;
    int i;
    for (i = 0; i < g.arcnum; i++)
    {
        int head, tail;
        float val;
        infile >> head >> tail >> val;  //文本里讀取文件到空格結(jié)束,循環(huán)結(jié)束以后進入到下一行
        g.AdjVector[head].vertex = head;   //這樣可以完成順序存放,這樣g.AdjVector[1]中,存放的是頭節(jié)點為1的結(jié)點,其他結(jié)點也都是對應(yīng)的
        Vertex_Value temp;
        temp.vertex = tail;
        temp.val = val;
        g.AdjVector[head].vec.push_back(temp);
    }
}
BasicFunctions.cpp
#include<algorithm>
#include <iterator> 
#include "UDG.h"
#include "BasicFunctions.h"



BasicFunctions::BasicFunctions(void)
{
}

BasicFunctions::~BasicFunctions(void)
{
}



//***********************************************************************
//判斷在圖g中結(jié)點u和結(jié)點v是否相連
bool BasicFunctions::IfConnect(int u, int v, UDG g)
{
    int i;
    unsigned int j;
    for (i = 1; i <= g.vernum; i++)
    {
        if (g.AdjVector[i].vertex == u)
        {
            break;
        }
    }

    for (j = 0; j < g.AdjVector[i].vec.size(); j++)
    {
        if (v == g.AdjVector[i].vec[j].vertex)
        {
            //cout << "結(jié)點" << u << "和結(jié)點" << v << "相連" << endl;
            return true;
        }
    }
    //cout << "結(jié)點" << u << "和結(jié)點" << v << "不相連" << endl;
    return false;
}




//***********************************************************************
//用在Enum_Deterministic中,更新其中的none集合
vector<int> BasicFunctions::GenerateNone(vector <int> all, vector <int> none, int v, UDG g)
{

    if (none.empty())
    {
        return none;
    }
    unsigned int i;
    vector<int> _none;
    for (i = 0; i < none.size(); i++)
    {
        if (IfConnect(v, none[i], g))
        {
            _none.push_back(none[i]);
        }
    }
    return _none;
}


//***********************************************************************
//用在Enum_Deterministic中,更新其中的some集合
vector<int> BasicFunctions::GenerateSome(vector <int> all, vector <int> some, int v, UDG g)
{
    if (some.empty())
    {
        return some;
    }
    unsigned int i ;
    vector<int> _some;
    for (i = 0; i < some.size(); i++)
    {
        if (IfConnect(v, some[i], g))
        {
            _some.push_back(some[i]);
        }
    }
    return _some;
}


//***********************************************************************
//用在Bron_Kerbosch算法中,枚舉圖中的極大團
void BasicFunctions::Enum_Deterministic(vector <int> all, vector <int> some, vector <int> none, UDG g)
{
    unsigned int i;
    if (some.empty() && none.empty())    //兩者都為空,則找到極大團
    {
        cout << "產(chǎn)生一個極大團!" << endl;
        for (i = 0; i < all.size(); i++)
        {
            cout << all[i] << ' ';
        }
        cout << endl;
        return;
    }
    int u; //選取Pivot結(jié)點
    if (!some.empty())//因為可能會存在著,some已經(jīng)為空了,但是none不為空的情況,這時,直接u=some[0]賦值,會報錯
    {
        u = some[0];     
    }

    vector<int> allTemp(all);   //將all中的所有值,都賦給allTemp,allTemp用來遞歸到下一層(去放置極大團)
    for (i = 0; i < some.size(); i++)
    {

        int v = some[i];
        if (IfConnect(u, v, g)) continue;  //如果u和v相連,就進入下一輪循環(huán),不再執(zhí)行下面代碼

        allTemp.push_back(some[i]);//更新下一層中的allTemp
        vector<int> _some = GenerateSome(allTemp, some, v, g);//產(chǎn)生新的some集合。要保證新的some集合,要和allTemp集合中的所有結(jié)點都連接
        vector<int> _none = GenerateNone(allTemp, none, v, g);//產(chǎn)生新的none集合。要保證新的none集合,要和allTemp集合中的所有結(jié)點都連接
        Enum_Deterministic(allTemp, _some, _none, g);   //帶著新的all,some,none集合進入到下一層中

        none.push_back(some[i]);//將some[i]放入none中,表示在這一層里面,由some[i]開始的極大團,已經(jīng)探索過了
        
        some[i] = 0;
        allTemp.pop_back(); //將some[i]從allTemp中拿出,開始下一輪的for循環(huán),在下一輪的for循環(huán)中,放入新的some[i]
    }

}



//***********************************************************************
//總算法的第一步,從原圖中得到所有的極大團子圖
void BasicFunctions::Bron_Kerbosch(const UDG g)
{


    vector <int> some(g.vernum);//聲明一個初始大小為g.vernum的Vertex_Value類型的向量_I,_I中存放的結(jié)點,就是預(yù)備要放入C中的
    vector<int> all;       //聲明一個int型向量all,就是極大團
    vector<int> none;   //聲明一個Vertex_Value型向量X ,X存放已經(jīng)探索過的某結(jié)點。
    int i = 1;
    for (i; i <= g.vernum; i++)
    {
        some[i - 1] = i;   //將所有的結(jié)點編號存放在some中
    }
    Enum_Deterministic(all, some, none, g);

}

下面是主函數(shù):

#include <tchar.h>
#include "ReadFile.h"
#include "BasicFunctions.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    UDG g;
    ReadFile A;
    A.CreateUdg(g);
    BasicFunctions BF;
    BF.Bron_Kerbosch(g);

    system("pause"); //暫停黑窗口
    return 0;
}

test.txt如下:
9表示結(jié)點數(shù),22表示邊數(shù)(這里的1 2和2 1算不同的邊)
第一位數(shù)字是頭結(jié)點,第二位數(shù)字是邊結(jié)點,第三個數(shù)字是邊上的概率

9 22
1 2 0.6
1 3 0.5
2 1 0.6
2 3 0.4
2 5 0.7
3 1 0.5
3 2 0.4
3 4 0.5
3 5 0.1
4 3 0.5
4 5 0.2
5 2 0.7
5 3 0.1
5 4 0.2
5 6 0.4
6 5 0.4
6 7 0.7
6 8 0.9
6 9 0.8
7 6 0.7
8 6 0.9
9 6 0.8

實驗結(jié)果:


實驗結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容