Warshell's Algorithms

来源:互联网 发布:网络连接图标是灰色的 编辑:程序博客网 时间:2024/05/22 08:11

学习离散数学的时候遇到了这个算法,此算法用于计算闭包矩阵(closure),其复杂度较普通的直接合并的方法要简单,为O(n^3),以下简单介绍一下这个算法~

(以下介绍传递闭包矩阵,其它类型的矩阵与传递闭包思想一致,且相对简单,大家可以自己写写)

1. 思想

2. 代码实现

i) 我们最初知道的仅仅是集合之间元素的关系,那么我们需要知道这个集合内有几个元素,并将它们赋值。

    cout<<"The number of element in your set: ";    int size;    cin>>size;    int mySet[size];    for (int i=0; i<size; i++) {        cout<<i+1<<". ";        cin>>mySet[i];    }

这个是非常简单的,就不作解释啦。

ii) 接下来,我们通过集合内元素的关系(relation)来生成关系矩阵,它是n*n的。

首先,我们需要user来告诉我们集合内元素的关系,我们需要定义一种表示关系的符号:

以下, 一组关系内部的两个元素用逗号(",")分隔, 关系之间用冒号(":")分隔。描述结束用q来标志结束。

如:  1,3 : 2,5 :3,2: 3,1 q

表示1到3为一组关系,2到5为一组关系(注意3到1与1到3是不同的关系),以此类推。

这是笔者自己定义的,你们可以自己定义。

这里还需要注意和说明几点:

a) 当user输入的关系中的某个元素是原来集合中没有的元素,我们就需要舍弃这组关系。

b) 这里是用new来声明二维数组,原因在于后面将要使用的函数,在后面会再提到。

    bool **mat=new bool *[size];    for (int i=0; i<size; i++) {        mat[i]=new bool[size];    }

c) 这里是用布尔数组,原因是这是一个0-1数组,后面在运算时也将有所简化。

下面是具体实现:

    bool **mat=new bool *[size];    for (int i=0; i<size; i++) {        mat[i]=new bool[size];    }    //preset the matrix to zero    for (int i=0; i<size; i++) {        for (int j=0; j<size; j++)            mat[i][j]=0;    }        //transfer relation to relation matrix    int temp;    char ch=0;    int li = 0,ri = 0;//to store the left value and right value in a relation    bool leftGood=false,rightGood=false,leftTurn=true;//good: the element exist;turn for left value to store->true    int index;//the index of the vl;    do {        cin>>temp;        if (cin.std::__1::ios_base::good()) {            if ((index=returnVl(temp, size, mySet))!=-1) {//if the value exist                if (leftTurn) {                    li=index;                    leftTurn=false;                    leftGood=true;                }else if(leftGood){                    ri=index;                    rightGood=true;                    leftTurn=true;                }            }else            {                if (leftTurn) {                    leftGood=false;                }else                {                    rightGood=false;                }            }        }else        {            cin.clear();            ch=cin.get();            if (ch!=',') {                if (leftGood&&rightGood) {                    mat[li][ri]=1;                    leftGood=rightGood=false;                }                leftTurn=true;            }        }    } while (ch!='q');

用到的检查是否含有该元素的函数定义(有则返回其index,无则返回-1,因为index不可能是-1):

int returnVl(int vl,int size,int *arr){    int i=0;    for (i=0; i<size&&vl!=arr[i]; i++) ;    if((i!=size)||(arr[size-1]==vl))    {        return i;    }else        return -1;}


这样我们就完成了从关系到关系矩阵的转换。
iii) 接下来我们要计算每一个warshell 矩阵。





复杂度:


这样,我们声明一个函数,来计算Wn.

void wsMat(bool **arr,int size,int n)//to acquire the nth warshall matrix{    for (int k=0; k<n; k++) {        for (int i=0; i<size; i++) {            for (int j=0; j<size; j++) {//                if (arr[i][j]==1||(arr[i][k]==1&&arr[k][j]==1)) {//                    arr[i][j]=1;//                }                arr[i][j]=arr[i][j]+arr[i][k]*arr[k][j];            }        }    }}
注释部分为原来的版本,因为是bool数组,修改为现有版本后变得尤为简洁。

现在来解释为什么前面要用new来声明数组,因为我们本可以使用

bool mat[size][size];

来声明。但是,在这里size作为一个variable,导致mat的类型不是bool **,所以在后面作为函数传入时IDE提示no matching function. 所以只能使用前面的方法。(这里笔者还要研究在深入一些)


iv) 输出结果



这里笔者加了3,6这组关系来测试是否会无视这对关系。


总结:

Warshell's Algorithms 的应用主要在于寻找最短路径。

1 0