离散数学--矩阵相乘算法与wa‘rshall算法求解传递闭包


一、啥是传递闭包?

概念:
“传递闭包、即在数学中,在集合X上的二元关系R的传递闭包是包含R的X上的最小的传递关系。” ——《百度百科》

人话 :
建立传递闭包的过程,就是给定一个有向(无向)图,对于节点 i 和节点 j ,如果他们联通但不直接相连,我们就建一个 i 到 j 的边.

二、求解算法

矩阵相乘累加关系幂算法

Warshall算法

Floyd算法

此算法代码过于简单,可是想到却不容易。建议通过传递关系的概念手动模拟。

三、话不多说直接上代码

//实现内容:
//矩阵输入输出、矩阵求幂、矩阵相乘、warshall算法求传递闭包
#include <iostream>
#include <vector>//此举原意在测试两算法时间复杂度时创建高阶矩阵
#define max 10 //定义常量 const int 亦可
using namespace std;
//创建矩阵类
class Matrix{
	private:
		int steps;//矩阵阶
		bool matrix[max][max];//原关系矩阵
		bool result2[max][max];//关系矩阵二次幂
		bool result3[max][max];//关系矩阵三次幂
		bool LastResult[max][max];//用以保存结果
	public:
        Matrix();//construstor
        Matrix(int steps);
		void get_steps();//用以手动输入阶数
		void input_matrix();//用以从键盘输入矩阵
		void output_matrix();//用以输出LastResult[][]
		void mult_matrix();//关系矩阵相乘累加以实现求解
		void warshall();//沃舍尔算法实现
	
};

    Matrix::Matrix()
	    {
			steps=max;
		}
		
	Matrix::Matrix(int steps)
		{
        	steps=steps;
		}
		
	void Matrix::get_steps()
        {
			cout<<"请输入矩阵的阶数"<<endl;
			int n;
			cin>>n;
			steps=n;
		}
		
	void Matrix::input_matrix()
		{
			cout<<"请输入矩阵: "<<endl;
			for(int i=0;i<steps;i++)
			 for(int j=0;j<steps;j++)
			  cin>>matrix[i][j];
			  cout<<"您输入的矩阵为:"<<endl;
			  for(int i=0;i<steps;i++)
			  {
			     	cout<<endl;
			  	for(int j=0;j<steps;j++)
	  			    cout<<matrix[i][j]<<" ";
			  }
			  cout<<endl;
			 
		}
		
	void Matrix::mult_matrix()
	{
//以下两个三层for循环可使用中间变量保存result2[][]
//在此基础上得出result3[][]=result2[][]*matrix[][] 可减少代码膨胀
	 for(int i=0;i<steps;i++)
			{
 		for(int j=0;j<steps;j++)
				{
			      bool sum=0;
				  	  for(int k=0;k<steps;k++)
					     {
						    sum+=(matrix[i][k]*matrix[k][j]);
				         }
						    result2[i][j]=sum;
				}
			}
			 if(steps>=3)
	for(int i=0;i<steps;i++)
			{
 		for(int j=0;j<steps;j++)
				{
			      bool sum=0;
				  	  for(int k=0;k<steps;k++)
					     {
						    sum+=(result2[i][k]*matrix[k][j]);
				         }
						    result3[i][j]=sum;
				}
			}
			
	for(int i=0;i<steps;i++)
		 {
		  for (int j=0;j<steps;j++)
		   {
		     if(steps==1) LastResult[i][j]=matrix[i][j];//这句几乎是不需要的,一阶矩阵即一个数

			 else if(steps==2) LastResult[i][j]=matrix[i][j]+result2[i][j];

			 else if(steps>=3) LastResult[i][j]=matrix[i][j]+result2[i][j]+result3[i][j];

		   }
         }

			
	}
	//沃舍尔算法,具体解析见教材或csdn
	void Matrix::warshall()
	{
		for(int k=0;k<steps;k++)
		 for(int i=0;i<steps;i++)
		  for(int j=0;j<steps;j++)
		  {
		  if(matrix[i][k]==1&&matrix[k][j]==1)
		        LastResult[i][j]=1;
		  }
	}
	//输出函数
	void Matrix::output_matrix()
	{
		for(int i=0;i<steps;i++){
			for(int j=0;j<steps;j++)
			cout<<LastResult[i][j]<<" ";
			cout<<endl;
		}		
	}

//主函数
int main(){
	Matrix M(4);
	M.get_steps();
	M.input_matrix();

	M.mult_matrix();
	cout<<"矩阵相乘算法得出的关系矩阵:"<<endl;
	M.output_matrix();

	M.warshall();
	cout<<"warshall算法得出的关系矩阵:"<<endl;
	M.output_matrix();
	
	return 0;
}

c++运行结果

在这里插入图片描述

四、jiva实现及算法时间复杂度比较

下面给出寝室大佬(其实是个撒币)的完整代码,说实话整挺好。

import java.util.Random;
import java.util.Scanner;
public class LiSan {
  public static void main(String[] args) {
    Random r = new Random(1);
    Scanner sc=new Scanner(System.in);
    int n=sc.nextInt();
    Warshall Wa=new Warshall(n);
    Matrix_Multi_Sum Ma=new Matrix_Multi_Sum(n);
    for(int i=1;i<=n;i++)
   {
      for (int j=1;j<=n;j++)
     {
        int x=sc.nextInt();
        Wa.setMatrix(i,j,x);
        Ma.setMatrix(i,j,x);
     }
   }
    System.out.println();
    long startTime11=System.nanoTime(); //获取开始时间
    Ma.set_Matrix_Multi_Sum();
    long endTime11=System.nanoTime(); //获取结束时间
    System.out.println("关系矩阵相乘运行时间: "+(endTime11-startTime11)+"ns");
    long startTime22=System.nanoTime(); //获取开始时间
    Wa.setWarshall();
    long endTime22=System.nanoTime(); //获取结束时间
    System.out.println("Warshall运行时间: "+(endTime22-startTime22)+"ns");
    System.out.println(n+"阶关系矩阵Warshall算法比关系矩阵相乘算法快"+((endTime11-
startTime11)/(endTime22-startTime22))+"倍");
    Wa.showWarshall();
    System.out.println();
    Ma.show_Matrix();
    System.out.println();
    System.out.println("判断两种算法得到的关系矩阵是否相同:"+Wa.Is_equal(Ma));
    for(int t=10;t<=300;t+=10) {
      Warshall Wa_Auto=new Warshall(t);
      Matrix_Multi_Sum Ma_Auto=new Matrix_Multi_Sum(t);
      for (int i = 1; i <=t; i++) {
        for (int j = 1; j <= t; j++) {
          int x1 = r.nextInt(2);
          Wa_Auto.setMatrix(i, j, x1);
          Ma_Auto.setMatrix(i, j, x1);
       }
     }
      System.out.println();
      startTime11 = System.nanoTime(); //获取开始时间
      Ma_Auto.set_Matrix_Multi_Sum();
      endTime11 = System.nanoTime(); //获取结束时间
       System.out.println("关系矩阵相乘运行时间:" + (endTime11 - startTime11)
+ "ns");
      startTime22 = System.nanoTime(); //获取开始时间
      Wa_Auto.setWarshall();
      endTime22 = System.nanoTime(); //获取结束时间
      System.out.println("Warshall运行时间: " + (endTime22 - startTime22) +
"ns");
      System.out.println(t + "阶关系矩阵Warshall算法比关系矩阵相乘算法快" +
((endTime11 - startTime11) / (endTime22 - startTime22)) + "倍");
      System.out.println("判断两种算法得到的关系矩阵是否相同:true" );
   }
 }
}
class Warshall{
  int [][]Matrix=new int[1001][1001];
  int n;
  Warshall(int n){
    this.n=n;
 }
  void setMatrix(int i,int j,int x)
 {
    Matrix[i][j]=x;
 }
  void setWarshall()
 {
    for (int i = 1;i<=n; i++)
   {
      for (int j = 1;j<=n; j++)
     {
        for(int k=1;k<=n;k++)
       {
          if(Matrix[j][i]==1&&Matrix[i][k]==1)
            Matrix[j][k]=1;
       }
     }
   }
 }
  void showWarshall()
 {
    for (int i = 1;i<=n; i++)
   {
      for (int j = 1;j<=n; j++)
     {
        System.out.print(Matrix[i][j]+" ");
     }
      System.out.println();
   }
 }
  boolean Is_equal(Matrix_Multi_Sum Ma){
    boolean Is=true;
    for(int i=1;i<=n;i++)
   {
      for(int j=1;j<=n;j++)
     {
         if (this.Matrix[i][j] != Ma.Matrix_sum[i][j]) {
          Is = false;
          break;
       }
     }
   }
    return Is;
 }
}
class Matrix_Multi_Sum{
  int [][]Matrix=new int[1001][1001];
  int [][]Matrix_double=new int[1001][1001];
  int [][]Matrix_sum=new int[1001][1001];
  int [][]Matrix_odd=new int[1001][1001];
  int [][]Matrix_even=new int[1001][1001];
  int n;
  Matrix_Multi_Sum(int n){
    this.n=n;
 }
  void setMatrix(int i,int j,int x)
 {
    Matrix[i][j]=x;
 }
  void set_Matrix_Multi_Sum()
 {
    for(int m=1;m<=n;m++)
   {
      if(m==2)
     {
        Matrix_square();
     }
      else if(m%2==1&&m!=1)
     {
        Matrix_Odd();
     }
      else if((m & 1) == 0)
     {
        Matrix_Odd();
        Matrix_Even(Matrix_odd, Matrix_even);
     }
      for(int i=1;i<=n;i++)
     {
        for (int j=1;j<=n;j++)
       {
          if(m==1) Matrix_sum[i][j]+=Matrix[i][j];
          else if(m==2) Matrix_sum[i][j]+=Matrix_double[i][j];
          else if((m&1)==1)Matrix_sum[i][j]+=Matrix_odd[i][j];
          else if((m&1)==0)Matrix_sum[i][j]+=Matrix_even[i][j];
       }
     }
   }
 }
  private void Matrix_Even(int[][] matrix_odd, int[][] matrix_even) {
     for(int i=1;i<=n;i++)
   {
      for(int j=1;j<=n;j++)
     {
        int sum=0;
        for(int k=1;k<=n;k++)
       {
          sum+=(matrix_odd[i][k]*Matrix[k][j]);
       }
        matrix_even[i][j]=sum;
     }
   }
 }
  private void Matrix_Odd() {
    Matrix_square();
    Matrix_Even(Matrix_double, Matrix_odd);
 }
  private void Matrix_square() {
    Matrix_Even(Matrix, Matrix_double);
 }
  void show_Matrix()
 {
    for (int i = 1;i<=n; i++)
   {
      for (int j = 1;j<=n; j++)
     {
        if(Matrix_sum[i][j]>1)Matrix_sum[i][j]=1;
        System.out.print(Matrix_sum[i][j]+" ");
     }
      System.out.println();
   }
 }
  boolean Is_equal(Matrix_Multi_Sum Wa){
    boolean Is=true;
    for(int i=1;i<=n;i++)
   {
      for(int j=1;j<=n;j++)
     {
        if (this.Matrix[i][j] != Wa.Matrix_sum[i][j]) {
          Is = false;
          break;
       }
     }
   }
    return Is;
 }
}

java运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

通过不同算法运行时间的比较,可见一个好的算法是多么的重要啊啊啊。
如需完整版c++实验报告请评论告知。
还请路过的大佬们评价指点。

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七月是你的谎言..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值