1. 程式人生 > 實用技巧 >離散數學實驗——關係及操作

離散數學實驗——關係及操作

3.1實驗目的

關係是集合論中的一個十分重要的概念,關係性質的判定是集合論中的重要內容。通過該組實驗,更加深刻地理解關係的概念和性質,並掌握關係性質的判定及關係的閉包的求法。

3.2實驗內容

1、鍵盤輸入集合A中的所有元素,並輸入關係R中的所有序偶對,建立關係R的關係矩陣;

2、判斷關係所具有的性質;

3、求關係R的逆關係,及關係的合成運算;

4、求關係R的r(R)、s(R)、t(R)。(注意關係的傳遞閉包採用Warshall演算法)。

5、判斷關係R是否為等價關係,若是等價關係,則求出其所有等價類;

6、選做:求集合A上的等價關係數

3.3主要演算法思想

1、鍵盤輸入集合A中的所有元素,並輸入關係R中的所有序偶對,建立關係R的關係矩陣;

①用字串ListA儲存集合A中所有元素,每個字元就是一個元素

②然後用List_Relation儲存關係R。

③然後定義一個方法建立關係R的關係矩陣。

2、判斷關係所具有的性質

關係性質的充要條件:

  設RA上的關係,
  (1) R
A上自反當且僅當 IAR
  (2) R
A上反自反當且僅當 RIA
  (3) R
A上對稱當且僅當 R=R-1
  
(4) R
A上反對稱當且僅當 RR-1IA
  (5) R
A上傳遞當且僅當 R°RR

判斷自反性:

///判斷自反性
///List_Relation是自反性說明 List_Relation包含集合A的恆等關係
///所以利用迴圈判斷每個元素
bool ReflexivityJudge(int** R) {
	for (int i = 0; i < ListA.length(); i++)
		if (R[i][i] == 0)
			return false;
	return true;
}

  

判斷反自反性:

///判斷反自反性
///R在A上反自反當且僅當  R∩IA=空集
///意思就是沒有一個環
bool InverserReflexivityJudge(int** R) {
	int n = ListA.length();
	for (int i = 0; i < n; i++) {
		if (R[i][i] == 1) return false;
	}
	return true;
}

  

判斷對稱性:

///判斷對稱性
///List_Relation滿足對稱性,則說明它的關係矩陣一定是對稱矩陣
bool SymmetryJudge(int** R) {
	for (int i = 0; i < ListA.length(); i++)
		for (int j = 0; j < i; j++)if (R[i][j] != R[j][i])return false;
	return true;
}

判斷反對稱性:

///判斷反對稱性
/// R在A上反對稱當且僅當 (R∩R的逆)包含於IA
/// 
bool InverseSymmtryJudge(int** R) {
	for (int i = 0; i < ListA.length(); i++)
		for (int j = 0; j < i; j++)if (R[i][j] == 1 && (R[i][j] == R[j][i]) && (i != j))return false;
	return true;
}

判斷傳遞性:

/// 判斷傳遞性
/// R在A上傳遞當且僅當 (R·R)包含於R 
bool TransitivityJudge(int** R) {
	int n = ListA.length();
	InitMatrix(S);
	Synthetise(R);//求R合成R,傳R進去,修改的是S
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (S[i][j] > R[i][j]) return false;
		}
	}
	return true;
}

3.4源程式及測試結果

3.5完整程式碼

#include <iostream>
#include <string>
using namespace std;


string ListA;//定義全域性集合
string List_Relation,List_InverseRelation;//定義全域性集合的關係和逆關係
int** R_Matrix,**R_InverseMatrix;//R_matrix為List_Relation的關係矩陣,R_InverseMatrix為逆關係矩陣,
int** S;//R合成R後的關係矩陣
char** EC;//等價關係R的等價類

//返回字元在集合中的下標
int Get_Index(string List, char ch)
{
	int i;
	for (i = 0; i < List.length(); i++)if (List[i] == ch)return i;
}
//初始化矩陣
void InitMatrix(int**& M) {
	int n = ListA.length();
	//動態建立二維陣列
	M = new int* [n];
	for (int i = 0; i < n; i++)
		M[i] = new int[n];
	//先將矩陣全置為0
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)M[i][j] = 0;
}

//輸入關係並建立關係矩陣
void CreateRelation()
{
	int x, y;//定義矩陣中的位置y代表行數,x代表列數
    //輸入關係有序偶對   請按照{<1,2>,<2,3>}輸入
	cout << "注:請按照{<1,2>,<2,3>}這種格式輸入" << endl;
	cout << "請輸入集合A上的關係R=";
    cin >> List_Relation;
	int n = List_Relation.length();
	InitMatrix(R_Matrix);//初始化矩陣

	for (int i = 2; i < n; i+=6) {
		y = Get_Index(ListA,List_Relation[i]);
		x = Get_Index(ListA, List_Relation[i + 2]);
		R_Matrix[y][x] = 1;
	}

}
//根據List_Relation得到它的逆關係List_InverseRelation和逆矩陣
void GetInverseRelation() {
	int n= ListA.length();
	List_InverseRelation = List_Relation;
	InitMatrix(R_InverseMatrix);
	R_InverseMatrix = R_Matrix;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (R_Matrix[i][j] != 0)
				R_InverseMatrix[j][i] = R_Matrix[i][j];
		}
	}

	for (int i = 2; i < n; i += 6) {
		char temp;
		temp = List_InverseRelation[i];
		List_InverseRelation[i] = List_InverseRelation[i + 2];
		List_InverseRelation[i + 2] = temp;
	}
}
//關係合成(只能自己合成自己)
//S是合成後的關係矩陣
void Synthetise(int **R) {
	int n = ListA.length();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (R[i][j] == 1) {
				for (int k = 0; k < n; k++) {
					if (R[k][i] == 1) S[k][j] = 1;
				}
			}

		}
	}
}
//生成R合成R後的關係字串
string GetSynthetiseStr(){
	int n = ListA.length();
	string SynthetiseStr;//R合成R後的關係字串
	SynthetiseStr = "{";
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++) {
			if (S[i][j] == 1) {
				SynthetiseStr = SynthetiseStr + "<" + ListA[i] + "," + ListA[j] + ">,";
			}
		}
	}
	SynthetiseStr.erase(SynthetiseStr.length() - 1, 1);
	SynthetiseStr += '}';
	return SynthetiseStr;
}


//輸出矩陣
void MatrixOut(int **M) {
	int n = ListA.length();
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cout << M[i][j] << " ";
		}
		cout << endl;
	}
}

#pragma region 關係的判斷
///判斷自反性
///List_Relation是自反性說明 List_Relation包含集合A的恆等關係
///所以利用迴圈判斷每個元素
bool ReflexivityJudge(int** R) {
	for (int i = 0; i < ListA.length(); i++)
		if (R[i][i] == 0)
			return false;
	return true;
}
///判斷反自反性
///R在A上反自反當且僅當  R∩IA=空集
///意思就是沒有一個環
bool InverserReflexivityJudge(int** R) {
	int n = ListA.length();
	for (int i = 0; i < n; i++) {
		if (R[i][i] == 1) return false;
	}
	return true;
}
///判斷對稱性
///List_Relation滿足對稱性,則說明它的關係矩陣一定是對稱矩陣
bool SymmetryJudge(int** R) {
	for (int i = 0; i < ListA.length(); i++)
		for (int j = 0; j < i; j++)if (R[i][j] != R[j][i])return false;
	return true;
}
///判斷反對稱性
/// R在A上反對稱當且僅當 (R∩R的逆)包含於IA
/// 
bool InverseSymmtryJudge(int** R) {
	for (int i = 0; i < ListA.length(); i++)
		for (int j = 0; j < i; j++)if (R[i][j] == 1 && (R[i][j] == R[j][i]) && (i != j))return false;
	return true;
}
/// 判斷傳遞性
/// R在A上傳遞當且僅當 (R·R)包含於R 
bool TransitivityJudge(int** R) {
	int n = ListA.length();
	InitMatrix(S);
	Synthetise(R);//求R合成R,傳R進去,修改的是S
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (S[i][j] > R[i][j]) return false;
		}
	}
	return true;
}
#pragma endregion

#pragma region 求關係的閉包
///自反閉包    相當於是求R和恆等關係的並集  直接把矩陣對角線的值置為1就行了
/// r(R)=R∪R^0
/// R^0=I(A)
void ReflexivityClosure() {
	string ReflexivityStr;//用來儲存自反閉包的集合字串	
	int n = ListA.length();
	//int** R;//自反閉包關係矩陣
	//R = new int* [n];
	//for (int i = 0; i < n; i++)R[i] = new int[n];
	//R = R_Matrix;
	ReflexivityStr = "{";
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++) {
			
			if (i == j) {
				cout << "1 ";
				ReflexivityStr = ReflexivityStr + "<" + ListA[i] + "," + ListA[j] + ">,";
				continue;
			}
			else cout << R_Matrix[i][j] << " ";
			if (R_Matrix[i][j] == 1) {//矩陣中為1的才有關係,則要儲存在集合字串中
				ReflexivityStr = ReflexivityStr + "<" + ListA[i] + "," + ListA[j] + ">,";
			}
		}
		cout << endl;
	}
	ReflexivityStr.erase(ReflexivityStr.length()-1,1);
	ReflexivityStr += '}';
	cout << "r(R)="<<ReflexivityStr;
}
///對稱閉包
/// 如果有<x,y>且沒有<y,x> 則新增<y,x>到集合中
/// s(R)=R∪R^-1
void SymmtryClosure() {
	string SymmtryStr;//用來儲存對稱閉包的集合字串
	int n = ListA.length();
	int** R;//對稱閉包關係矩陣
	R = new int* [n];
	for (int i = 0; i < n; i++)R[i] = new int[n];
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			R[i][j] = R_Matrix[i][j];
	SymmtryStr = "{";
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			//關係中如果有<x,y>且沒有<y,x> 則新增<y,x>到集合中
			if (R[i][j] == 1 && R[j][i] != 1) {
				R[j][i] = 1;
			}
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cout << R[i][j] << " ";
			if (R[i][j] == 1)
			{
				SymmtryStr = SymmtryStr + "<" + ListA[i] + "," + ListA[j] + ">,";
			}
		}
		cout << endl;
	}
	SymmtryStr.erase(SymmtryStr.length() - 1, 1);
	SymmtryStr += '}';
	cout << "s(R)=" << SymmtryStr;
}

///傳遞閉包(採用Warshall演算法)
/// t(R)=R∪R^2∪R^3∪…
void TransitivityClosure() {
	string TransitivityStr;//用來儲存對稱閉包的集合字串
	int n = ListA.length();
	int** R;//對稱閉包關係矩陣
	R = new int* [n];
	for (int i = 0; i < n; i++)R[i] = new int[n];
	for (int i = 0; i < n; i++)
		for(int j=0;j<n;j++)
			R[i][j] = R_Matrix[i][j];
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (R[j][i]==1)
			{
				for (int k = 0; k < n; k++)
				{
					R[j][k] = R[j][k] | R[i][k];//邏輯加 
				}
			}
		}
	}
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			cout << R[i][j] << " ";
			if (R[i][j] == 1)
			{
				TransitivityStr = TransitivityStr + "<" + ListA[i] + "," + ListA[j] + ">,";
			}
		}
		cout << endl;
	}
	TransitivityStr.erase(TransitivityStr.length() - 1, 1);
	TransitivityStr += '}';
	cout << "t(R)=" << TransitivityStr;
}
#pragma endregion

///判斷關係R是否為等價關係
/// 如果R同時滿足自反、對稱、傳遞則是等價
bool EqualJudge(int **R) {
	if (ReflexivityJudge(R_Matrix) && SymmetryJudge(R_Matrix) && TransitivityJudge(R_Matrix))
		return true;	
	else
		return false;
}

/// 求出所有等價類
/// 如果<x,y>∈R,則說明x,y在同一個等價類
/// 例如:等價關係R={<1,2><2,1><1,3><3,1><2,3><3,2><4,5><5,4>}∪IA
/// 則等價類有兩個{1,2,3},{4,5}
void GetEqualClass(int **R) {
	int n = ListA.length();
	string A = ListA;
	EC = new char*[n];//最大的等價類個數就是元素個數
	int Num=0;//等價類個數
	int ip;
	for (int i = 0; i < n; i++) {
		if (A[i]) {
			ip = 0;
			EC[Num] = new char[n];
			EC[Num][ip++] = A[i];
			for (int j = i + 1; j < n; j++) {
				if (A[i] && R[i][j]) {
					EC[Num][ip++] = A[j];
					A[j] = 0;
				}
			}
			EC[Num][ip] = '\0';
			Num++;
		}
		
	}
	cout << "等價類有" << Num << "個,分別是";
	for (int i = 0; i < Num; i++) {
		cout << "{";
			for (int j = 0; j < strlen(EC[i]); j++) {
				if (j == strlen(EC[i]) - 1)
					cout << EC[i][j];
				else
					cout << EC[i][j] << ",";	
		}
		cout << "}  ";
		}
}


/// 求出等價關係數
/// 算等價關係數相當於是算有多少種組合,又因為集合A的等價關係與劃分個數是一一對應的,因此求其劃分個數即可
/// 在有n個元素的集合裡面,有1個元素的劃分、2個元素的劃分.....到n個元素的劃分
/// 最後再把所有劃分的個數加起來
/// 等價關係數=S(n,1)+S(n,2)+.....+S(n,n)
void GetEqualClassNum() {
	int allNum=0;
	int n = ListA.length();
	for (int i = 1; i <= n; i++)
		allNum += Stirling(n, i);
	cout << "集合A的等價關係有" << allNum << "個;";
}


//建立集合
void ListCreat() {
	while (true)
	{
		cout << "請輸入集合A的的元素:";
		cin >> ListA;
		bool flag;
		for (int j = 0; j < ListA.length(); j++) {
			flag = true;
			for (int k = j + 1; k < ListA.length(); k++) {
				if (ListA[j] == ListA[k])
				{
					flag = false;
					break;
				}
			}
			if (!flag)
				break;
		}
		if (!flag) {
			cout << "集合中不允許存在相同元素!,請重新輸入!" << endl;;
		}
		else
		{
			break;
		}
	}
}
void main() {	
	//1、鍵盤輸入集合A中的所有元素,並輸入關係R中的所有序偶對,建立關係R的關係矩陣
	cout << "1、鍵盤輸入集合A中的所有元素,並輸入關係R中的所有序偶對,建立關係R的關係矩陣;" << endl;
	ListCreat();
	CreateRelation();
	cout << "關係R的關係矩陣:" << endl;
	MatrixOut(R_Matrix);


	//2、判斷關係所具有的性質
	cout << endl << "2、判斷關係所具有的性質" << endl;
	cout << "關係R:" << endl;
	cout << "*****************\n";
	if (ReflexivityJudge(R_Matrix))
		cout << "具有自反性\t*" << endl;
	if(InverserReflexivityJudge(R_Matrix))
		cout << "具有反自反性\t*" << endl;
	if (SymmetryJudge(R_Matrix))
		cout << "具有對稱性\t*" << endl;
	if (InverseSymmtryJudge(R_Matrix))
		cout << "具有反對稱性\t*" << endl;
	if (TransitivityJudge(R_Matrix))
		cout << "具有傳遞性\t*" << endl;
	cout << "*****************\n";

	//3、求關係R的逆關係,及關係的合成運算;
	cout << endl << "3、求關係R的逆關係,及關係的合成運算" << endl;
	GetInverseRelation();
	cout << "關係R的逆關係=" << List_InverseRelation << endl;
	cout << "關係R的逆關係矩陣:" << endl;
	MatrixOut(R_InverseMatrix);
	cout << "R·R(R合成R)後的關係=" << GetSynthetiseStr() << endl;
	cout << "R·R(R合成R)後的關係矩陣:" << endl;
	MatrixOut(S);

	//4、求關係R的r(R)、s(R)、t(R)
	cout << endl << "4、求關係R的r(R)、s(R)、t(R)" << endl;
	cout << "自反閉包矩陣:" << endl;
	ReflexivityClosure();
	cout << endl;
	cout << "對稱閉包矩陣:" << endl;
	SymmtryClosure();
	cout << endl;
	cout << "傳遞閉包矩陣:" << endl;
	TransitivityClosure();
	cout << endl;

	//5、判斷關係R是否為等價關係,若是等價關係,則求出其所有等價類
	cout <<endl<< "5、判斷關係R是否為等價關係,若是等價關係,則求出其所有等價類" << endl;
	cout << "關係R";
	if (EqualJudge(R_Matrix)) {
		cout << "是等價關係\n";
		GetEqualClass(R_Matrix);
	}
	else
		cout << "不是等價關係";
	cout << endl;
}