离散数学实验2关联矩阵相邻矩阵

代码展示 

#include <iostream>
using namespace std;
int XLmatrix[100][100] = { 0 };//输入的相邻矩阵
int n;//点数
int m;//边数
int m_tee = n - 1;
int  GLmatrix[100][100] = { 0 };//输出的关联矩阵
int GL_copy[100][100] = { 0 };//复制关联矩阵
int XL_copy[100][100] = { 0 };//复制相邻矩阵的值
int D[100][100] = { 0 };//度数矩阵
int K[100][100] = { 0 };//基尔霍夫矩阵
int k_n[100][100] = { 0 };//基尔霍夫矩阵的n-1阶矩阵
int Tree_XL[100][100] = { 0 };//树的相邻矩阵
int tree_xl[100][100] = { 0 };//复制的树的相邻矩阵
int Tree_GL[100][99] = { 0 };//树的关联矩阵
int tree_gl[100][100] = { 0 };//复制的数的关联矩阵
int Circle[100][100] = { 0 };//基本回路系统
int Huanlu[100][100] = { 0 };//环路空间
int CutGather[20][20] = { 0 };//断集空间
int Duanji[100][100] = { 0 };//基本割集系统
int HLMatrix[10][100]={0};//回路信息储存矩阵
struct Bian
{
	int u;//起点
	int v;//终点
	int num;//边的编号
}bian[20];
int fa[20];
//输入1是复制相邻矩阵,输入2是复制关联矩阵//输入3是求基尔霍夫矩阵的余子式//4复制树的相邻矩阵5复制树的关联矩阵
void Copy_X(int sign)
{
	if (sign == 1)
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
				XL_copy[i][j] = XLmatrix[i][j];
		}
	}
	else if (sign == 2)
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
				GL_copy[i][j] = GLmatrix[i][j];
		}
	}
	else if (sign == 3)
	{
		for (int i = 1; i < n; i++)
		{
			for (int j = 1; j < n; j++)
			{
				k_n[i - 1][j - 1] = K[i][j];
			}
		}
	}
	else if (sign == 4)
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
				tree_xl[i][j] = Tree_XL[i][j];
		}
	}
	else if (sign == 5)
	{
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n - 1; j++)
				tree_gl[i][j] = Tree_GL[i][j];
		}
	}
}
//求基尔霍夫矩阵
void XLTOGL()
{
	int j = 0;//关联矩阵中的列
	//复制相邻矩阵
	Copy_X(1);
	//相邻矩阵变成关联矩阵
	for (int i = 0; i < n; i++)
	{
		for (int k = 0; k < n; k++)
		{
			//生成度数矩阵
			D[i][i] += XLmatrix[i][k];
			//对输入矩阵中的不大于1的度数的点的处理
			if(XL_copy[i][k]==1)
			{
				if (XL_copy[i][k] == 1)
				{
					XL_copy[i][k] = 0;
					XL_copy[k][i] = 0;
					GLmatrix[i][j] = 1;
					GLmatrix[k][j] = 1;
					//创建bian这个结构体
					if (i < k)
					{
						bian[j].u = i;
						bian[j].v = k;
					}
					else if (i >= k)
					{
						bian[j].u = k;
						bian[j].v = i;
					}
					//边的标号值
					bian[j].num = j + 1;
					j++;
				}
			}
			else if(XL_copy[i][k]>1)
			{
				while(XL_copy[i][k] > 0)
				{
					GLmatrix[i][j] = 1;
					GLmatrix[k][j] = 1;
					if (i < k)
					{
						bian[j].u = i;
						bian[j].v = k;
					}
					else if (i >= k)
					{
						bian[j].u = k;
						bian[j].v = i;
					}
					//边的标号值
					bian[j].num = j + 1;
					j++;
					XL_copy[i][k]--;
					XL_copy[k][i]--;
				}
			}
		}
	}
	//树相邻矩阵变成关联矩阵
	for (int i = 0; i < n; i++)
	{
		for (int k = 0; k < n; k++)
		{
			if (tree_xl[i][k] == 1)
			{
				tree_xl[i][k] = 0;
				tree_xl[k][i] = 0;
				Tree_GL[i][j] = 1;
				Tree_GL[k][j] = 1;
				j++;
			}
		}
	}
	Copy_X(1);
	Copy_X(2);
	//基尔霍夫矩阵的n-1阶
}
//打印树的矩阵,其中包括生成基尔霍夫矩阵
void PrintGraph()
{
	//基尔霍夫矩阵
	for (int i = 0; i < n; i++)
	{
		for (int k1 = 0; k1 < n; k1++)
		{
			K[i][k1] = D[i][k1] - XLmatrix[i][k1];
		}
	}
	cout << "关联矩阵" << endl;
	for (int i = 0; i < n + 1; i++)
	{
		if (i == 0)
		{
			for (int j = 0; j < m; j++)
			{
				if (j == 0)
					cout << "   ";
				cout << "e" << j + 1 << " ";
			}
		}
		else
		{
			for (int j = 0; j < m + 1; j++)
			{
				if (j == 0)
				{
					cout << "v" << i << " ";
				}
				else
					cout << GLmatrix[i - 1][j - 1] << "  ";
			}
		}
		cout << endl;
	}
	cout << "生成树的相邻矩阵" << endl;
	for (int i = 0; i < n + 1; i++)
	{
		if (i == 0)
		{
			for (int j = 0; j < n; j++)
			{
				if (j == 0)
					cout << "   ";
				cout << "v" << j + 1 << " ";
			}
		}
		else
		{
			for (int j = 0; j < n + 1; j++)
			{
				if (j == 0)
				{
					cout << "v" << i << " ";
				}
				else
					cout << Tree_XL[i - 1][j - 1] << "  ";
			}
		}
		cout << endl;
	}
	cout << "生成树关联矩阵" << endl;
	for (int i = 0; i < n + 1; i++)
	{
		if (i == 0)
		{
			for (int j = 0; j < m; j++)
			{
				if (j == 0)
					cout << "   ";
				if (bian[j].num < 0)
				{
					cout << "e" << j + 1 << " ";
				}
				else
				{
					continue;
				}
			}
		}
		else
		{
			for (int j = 0; j < m+1; j++)
			{
				if (j == 0)
				{
					cout << "v" << i << " ";
				}
				else if (bian[j - 1].num < 0)
				{
					cout << Tree_GL[i - 1][j - 1] << "  ";
				}
				else
					continue;
			}
		}
		cout << endl;
	}
	cout << "------------------------" << endl;
}
//用基尔霍夫矩阵计算生成树的个数
int laplace_expansion(int matrix[100][100], int r, int c, int order);
//用基尔霍夫矩阵计算生成树的个数
int GetTreeNum(int matrix[100][100], int order)
{
	int result = 0, sign = 1, cofactor, i;
	if (order == 1)
		result = matrix[0][0];
	else
		for (i = 0; i < order; i++)
		{
			cofactor = laplace_expansion(matrix, i, 0, order);
			result += sign * matrix[i][0] * cofactor;
			sign *= -1;
		}
	return result;
}
int laplace_expansion(int matrix[100][100], int r, int c, int order)
{
	int result = 0, cofactor[100][100], original_i, original_j, i, j;
	for (i = 0; i < order; i++)
		for (j = 0; j < order; j++)
		{
			original_i = i;
			original_j = j;
			if (i == r || j == c);
			else
			{
				if (i > r)
					i--;
				if (j > c)
					j--;
				cofactor[i][j] = matrix[original_i][original_j];
				i = original_i;
				j = original_j;
			}
		}
	if (order >= 2)
		result = GetTreeNum(cofactor, order - 1);
	return result;
}
//用克鲁斯卡尔并查集的方式
//并查集查找
//祖先
int Find(int x)
{
	return x == fa[x] ? x : Find(fa[x]);
}
//初始化fa数组
void init()
{
	for (int i = 0; i < n; i++)
	{
		fa[i] = i;
	}
	return;
}
//用并查集的方式,获取一个树
int GetOneTree()
{
	init();
	int cnt = 0;
	int t = 0;
	for (int i = 0; i < m; i++)
	{
		Bian e = bian[i];
		int x = Find(e.u);
		int y = Find(e.v);
		if (x != y) 
		{//如果父节点相同,则构成了一个环,那么就不能将其放入里面,跳过
			Tree_XL[bian[i].u][bian[i].v] = 1;
			Tree_XL[bian[i].v][bian[i].u] = 1;
			Tree_GL[bian[i].u][i] = 1;
			Tree_GL[bian[i].v][i] = 1;
			cnt += e.num;
			fa[x] = y;//小的父亲是大的
			//树枝
			bian[i].num = -1 * bian[i].num;
			t++;
		}
		if (t == n - 1) break;//如果所加的边达到了n-1条,跳出循环
	}
	return cnt;
}
int v[100] = { 0 }, top = 0; int vispath[20][20] = { 0 };
int vispath2[20][20] = { 0 };
//在树中找到一个访问的点
void dfs(int sign, int pos, int end)//从pos点开始访问
{
	int i;
	//到达终点
	if (pos == end)
	{
		vispath[sign][top++] = end;
		
		vispath[sign][top] = -1;
		for (i = 0; i < top+1; i++)
		{
			vispath2[sign][i] = vispath[sign][i];
		}
		return;
	}
	else
	{
		v[pos] = 1;//标记被访问过 
		vispath[sign][top++] = pos;//经过的路径加入队列
		for (i = 0; i < n; i++)
		{
			if (!v[i] && tree_xl[pos][i] == 1)//如果这个点没有被访问过,而且b与这个点相连,就继续搜索
			{
				dfs(sign, i, end);
			}
		}
		v[pos] = 0;//删除标记 
		top--;//队列里删除b
	}
}
//基本回路系统用DFS获取在树中走过的点
void BasicCircle()
{
	Copy_X(4);
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < 10; j++)
			v[j] = 0;
		//弦
		if (bian[i].num > 0)
		{
			top = 0;
			dfs(i, bian[i].u, bian[i].v);
		}
	}
}
int sign = -1;
//经过的点变成边路径储存
void PointToPath()
{
	for (int i = 0; i < m; i++)
	{
		//找到弦所对应点集合
		if (bian[i].num < 0)
		{
			sign = sign;
			continue;
		}
		else
			sign++;
		//将点集合复制变成回路
		for (int j = 0; j < n + 2; j++)
		{
			if (vispath2[i][j] == -1)
				break;
			int x = vispath2[i][j] < vispath2[i][j + 1] ? vispath2[i][j] : vispath2[i][j + 1];
			int y = vispath2[i][j] >= vispath2[i][j + 1] ? vispath2[i][j] : vispath2[i][j + 1];
			for (int k = 0; k < m; k++)
			{
				if (bian[k].u == x && bian[k].v == y && bian[k].num < 0)
				{
					Circle[sign][j] = abs(bian[k].num);
					break;
				}				
			}	
			Circle[sign][j + 1] = abs(bian[i].num);
		}	
	}
}
void CircleToHLmatrix()
{
	for (int i = 0; i < m-n+1; i++)
	{
		for (int j = 0; j < m; j++)
		{
			if (Circle[i][j] != 0)
			{
				HLMatrix[i][Circle[i][j] - 1] = 1;
			}
			else
				continue;
		}
	}
}
//环路空间
int cal[100];
void HuanCircleRoad()
{
	printf("\n环路空间:{空");
	int sx = pow(2, m-n+1);
	for(int i=1;i<sx;i++)
	{
		memset(cal, 0, sizeof(cal));
		int  fakei = i;
		for (int j = 0; j < m-n+1; j++)
		{
			if (fakei % 2 != 0)
			{
				for (int k = 0; k < m; k++)
					cal[k] += HLMatrix[j][k];
			}
			fakei/=2;
		}
		//共有m条边选择输出
		printf(",");
		for (int k = 0; k < m; k++)
		{
			if (cal[k]%2!=0||cal[k]==1)
				printf("e%d", k+1);
		}		
	}
	printf("}\n");
}
//基本割集系统
int kD = 0; int kd2=0;
int part1[100]={0}; /*第一个连通分支所具有的点的编号*/int part2[100]={0};/*第二个连通分支所具有的点的编号*/
//找到可以和某点连通的函数
//用DFS储存
int vis[10] = { 0 };
//找到去掉一个弦之后的俩个连通分支
void DFS(int x,int a[100][100] )
{  
	vis[x] = 1;
	for (int i = 0; i < n; i++)
	{
		if (vis[i] == 0 && a[x][i] == 1)
			DFS(i,a);
	}
}
int k22=0;
void FindConnet(int x,int *a,int b[100][100])
{
	for (int i = 0; i < n+1; i++)
		vis[i] = 0;
	DFS(x,b);
	for (int l= 0; l < n; l++)
	{
		if (vis[l] == 1)
		{
			a[k22] = l+1;
			k22++;
		}
	}
	k22 = 0;
}
//在原图中找到连通俩个分支的边.找到弦
void FindConnectEdge(int z)
{

	int d = 1;
	for (int i = 0; i < m; i++)
	{
		//因为要是弦所以找到的点的编号应该是大于0的
		if (bian[i].num > 0)
		{
			for (int j = 0; j < n; j++)
			{
				if (part1[j] == 0)
					break;
				for (int k = 0; k < n; k++)
				{
					if (part2[k] == 0)
						break;
					int x = part1[j] < part2[k] ? part1[j] : part2[k];
					int y= part1[j] > part2[k] ? part1[j] : part2[k];	
					if (bian[i].u == x-1 && bian[i].v == y-1)
					{
						Duanji[z][d] = bian[i].num;
						d++;
					}
				}			
			}
		}
	}
}
int keyduan = 0;
void Duan()
{
	for (int i = 0; i < m; i++)
	{
		//复制树的相邻矩阵
		Copy_X(4);
		//找到树枝
		if (bian[i].num < 0)
		{
			//除去其中的一根树枝树枝
			tree_xl[bian[i].u][bian[i].v] = 0;
			tree_xl[bian[i].v][bian[i].u] = 0;
			//去掉一根树枝一定会让生成树的图内被分成俩个连通分支;
			//一个是和bian[i].u相连的点在一个连通分支
			//另一个是bian[i].v的点在的一个连通分支
			//找到俩个连通分支
			FindConnet(bian[i].u, part1,tree_xl);
			FindConnet(bian[i].v, part2,tree_xl);
			Duanji[keyduan][0] = -1*bian[i].num;
			FindConnectEdge(keyduan);
			keyduan++;
			for (int k = 0; k < n+1; k++)
			{
				part1[k] = 0;
				part2[k] = 0;
			}
		}
	}
}
//对称差运算
int DUanmatrix[10][10];
void DUANJIMatrix()
{
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < m; j++)
		{
			if (Duanji[i][j] != 0)
			{
				DUanmatrix[i][Duanji[i][j] - 1] = 1;
			}
		}
	}
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < m; j++)
		{
			printf("%d ", DUanmatrix[i][j]);
		}
		cout << endl;
	}
}
//断集合,树枝对应的个数
int duancal[10] = {0};
void BasicCutGather()
{
	int k = n - 1;
	DUANJIMatrix();
	printf("\n断集空间:{");
	int sx = pow(2,n-1);
	for (int i = 1; i < sx; i++)
	{
		memset(duancal, 0, sizeof(duancal));
		int  fakei = i;
		for (int j = 0; j < k; j++)
		{
			if (fakei % 2 != 0)
			{
				for (int k = 0; k < m; k++)
					duancal[k] += DUanmatrix[j][k];
			}
			fakei /=2;
		}
		printf("{");
		for (int k = 0; k < m; k++)
		{
			if (duancal[k] % 2 != 0 || duancal[k] == 1)
				printf("e%d,", k + 1);
		}
		printf("}");
	}
	printf("{ }}\n");
}
//打印基本回路,基本割集系统,环路空间,断集合控件
void PrintCircle()
{
	BasicCircle();
	PointToPath();
	int key = 0;
	cout << "基本回路系统:";
	cout << "{";
	for (int i = 0; i < sign+1; i++)
	{
		for (int j = 0; j < m; j++)
		{
			if (Circle[i][j] == 0 || (Circle[i][j - 1] == Circle[i][j]))
			{
				Circle[i][j] = 0;
				break;
			}

			cout <<"e" << Circle[i][j] ;

		}
		cout << ",";
	}
	cout << "}" << endl;
	CircleToHLmatrix();
	cout << "矩阵表示基本回路系统" << endl;
	for (int i = 0; i < m - n + 1; i++)
	{
		for (int j = 0; j < m; j++)
			cout <<HLMatrix[i][j] << " ";
		cout << endl;
	}
	HuanCircleRoad();
	cout << "\n";
	cout << "---------------------------" << endl;
	cout << "基本割集系统" << endl;
	Duan(); cout << "{";
	int j;
	for (int i = 0; i < n-1; i++)
	{
		cout << "{";
		for ( j = 0; j < n; j++)
		{
			if (Duanji[i][j+1] != 0)
				cout << "e" << Duanji[i][j]<<",";
			else
				break;
		}
		cout<<"e" << Duanji[i][j] << "}";
	}
	cout << "}" << endl;
	BasicCutGather();
}
void test()
{
	cout << "请输入阶数" << endl;
	cin >> n;
	cout << "输入相邻矩阵" << endl;
	//构建相邻矩阵以及输入矩阵
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> XLmatrix[i][j];
		}
	}
	//求边数
	int sumdiv = 0;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			sumdiv += XLmatrix[i][j];
	m = sumdiv / 2;
	XLTOGL();
	int a = GetOneTree();
	PrintGraph();
	Copy_X(1);
	Copy_X(3);
	int num = GetTreeNum(k_n, n - 1);
	cout << "生成树的个数为:" << num << endl;
	cout << "----------------------------------" << endl;
	PrintCircle();
}
int main()
{
	test();
}

代码思路:

1.关于生成树的问题

用并查集进行找到每个点的父亲,只要每个点的父亲不一样,即证明需要连接这俩个点,即证明是连通的

2.关于找到生成树个数的问题,

所采用的方法是基尔霍夫矩阵的n-1阶主子式的行列式的值就是个数

3.关于产生基本回路系统的处理

在进行基本回路系统查找的时候,我采取的是先进行在原图中删弦,然后开始在树中查找这个弦对应的边,之后将经过的点转成边,储存即可

4关于由基本回路系统生成环路空间

用的是选择相加,先把基本回路系统对应的边变成矩阵

5.关于基本割集系统的形成

我所想的是在原图中删除一条边那么一定会在树中产生俩个连通分支,找到这俩个连通分支的点,然后在边中进行遍历查找,只要有边一个端点是其中一个连通分支的点,边的另一个点是另一个连通分支中的点,即证明此边是基本割集系统中的边。

6.关于基本割集系统变成断集空间

采用的是对称差,和基本回路系统变成环路空间差不多

结果展示

对于有平行边的图 

对于没有平行边的图

 本段代码并没有一些高级的算法,或者高级的东西,唯二用到就是并查集和DFS此俩种算法建议同学了解之后再看代码,另外此代码方便初学者学习,因为没有过多复杂的东西,思路都是很简单的

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值