洛谷:矩阵相乘

本文介绍了如何通过创建一个简单的向量类并重载乘法运算,将矩阵的乘法转换为行向量和列向量的相乘,展示了如何在C++中实现这一过程并管理内存。

如图所示,这是一道关于矩阵乘法的问题,当然,学过线性代数之后,我们对于矩阵的乘法已经有了一个明确的概念,这个地方不再赘述,我在这里想提出的是另一个角度——向量

我们知道,矩阵本身可以写成向量组的形式,对于矩阵的乘法,其实也可以看作左边矩阵的行向量组和右边矩阵的列向量组的相乘结果

那么,我们就不妨自己写一个向量类(当然,这个向量不是vector),重载向量的乘法,这样的话就可以得到矩阵的乘积了

上代码吧

#include <bits/stdc++.h>
using namespace std;
//创建一个向量类 
class vec
{
	private:
		int a[100];
		int size;
	public:
		vec()                       //默认构造,向量维数为0 
		{
			size=0;
		}
		void add(int x)             //对向量进行补充完善 
		{
			a[size]=x;
			size++;
		}
		int operator*(const vec &v) //重载向量的乘法 
		{
			int sum=0;
			for(int i=0;i<size;i++)
			{
				sum+=a[i]*v.a[i];
			}
			return sum;
		}
}; 
int main()
{
	int m,n,k;
	cin>>m>>n>>k;//m个行向量,k个列向量
	//创建两个向量组
	vec *v1=new vec[m];
	vec *v2=new vec[k];
	//先对第一个向量组进行完善 
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
		{
			int x;
			cin>>x;
			v1[i].add(x);
		}
	} 
	//接着完善第二个向量组,因为输入顺序原因,需要二维数组保存矩阵信息,然后再录入
	int **p=new int *[n];
	for(int i=0;i<n;i++)
	{
		p[i]=new int [k];
	} 
	//保存矩阵信息 
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<k;j++)
		{
			cin>>p[i][j];
		}
	}
	//录入向量组
	for(int i=0;i<k;i++)
	{
		for(int j=0;j<n;j++)
		{
			v2[i].add(p[j][i]);
		}
	} 
	//再录入之后,数组就没啥用了,所以可以直接释放 
	for(int i=0;i<n;i++)
	{
		delete []p[i];
	}
	delete []p;
	//接着进行向量组的相乘运算
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<k;j++)
		{
			cout<<v1[i]*v2[j]<<" ";
		}
		cout<<endl;
	} 
	//好习惯:用完之后释放内存 
	delete []v1;
	delete []v2;
	return 0;
}

<think>好的,我现在需要解决用户关于B2100题目的问题。首先,用户希望查找该题目的相关信息或解法。根据用户提供的引用内容,我需要先理解题目要求,然后分析正确的解决方法。 首先,题目要求输入三个自然数N、i、j,输出与格子(i,j)同行、同列、同一对角线的所有格子位置。输出分为四部分:同行、同列、左上到右下的对角线、左下到右上的对角线,每部分占一行,格子位置按特定顺序排列,格式为(x,y)。 接下来,我需要确认题目中的具体要求。引用[3]提到输出格式的四个部分,并且每个位置用括号括起来,中间无空格,相邻位置用空格分隔。例如,同一行的格子是从左到右输出,也就是列号从1到N依次增加。而同一列则是从上到下,行号从1到N。对于对角线部分,左上到右下的对角线满足行号减列号的差等于i-j,而左下到右上的对角线满足行号加列号等于i+j。不过,这里需要注意输出顺序,左上到右下需要按左上到右下的顺序,即行号递增;左下到右上则需要从左上到右下,但根据引用[4]的代码,左下到右上可能是从下往上输出行号,因此可能需要逆序处理。 然后,我需要验证引用中的代码是否正确。例如,引用[4]中的C代码处理同一行和列时,使用循环直接输出a行和b列的所有位置。对于对角线部分,左上到右下使用双重循环遍历所有格子,检查i-j是否等于a-b,这样会收集到所有符合条件的格子,但输出顺序可能不是按照从左上到右下的顺序,因为双重循环是按行和列的顺序遍历的,可能需要进一步调整顺序以确保输出顺序正确。例如,对于左上到右下对角线,正确的顺序应该是行号递增,因此可能需要找到起始点,然后依次输出每个符合条件的格子,而不是遍历整个矩阵。同样,左下到右上的对角线需要从左上开始,即行号从高到低或列号从低到高,需要确认代码是否正确处理了顺序。 在引用[4]的代码中,处理左上到右下对角线时,使用双重循环遍历所有i和j,当i-j等于a-b时输出,这样可能会得到多个符合条件的点,但顺序是按行优先遍历,可能不是按照对角线从左到右的顺序。例如,当N=5,i=3,j=3时,对角线上的点应该是(1,1),(2,2),(3,3),(4,4),(5,5),而代码的遍历方式可能会按行号1到5,列号1到5的顺序检查,因此输出顺序是正确的。而左下到右上的对角线在代码中是外层循环i从n到1,内层j从1到n,当i+j等于a+b时输出,例如i=5,4,3,…,这样输出的顺序会是(5,1),(4,2),(3,3),(2,4),(1,5),即从下到上的行号,符合从左下到右上的顺序,即左上方向开始,但实际题目要求的输出顺序可能需要从左下到右上,即(3,3)的上方和下方如何排列。例如,如果i=3,j=3,那么左下到右上的对角线点可能包括(5,1),(4,2),(3,3),(2,4),(1,5),而输出顺序需要是从左上到右下,也就是从(1,5)到(5,1)吗?或者需要按从下到上的顺序?需要根据题目输出样例来判断。 假设题目中的输出示例可能要求第三行左上到右下按行号递增,第四行左下到右上也按行号递减,比如从(5,1)到(1,5),那么引用[4]的代码处理第四部分时,i从n到1循环,j从1到n,这样当i+j等于a+b时,会先找到较大的i值,即从下往上输出,例如当a=3,b=3,i从5到1,当i=5时j=1,满足5+1=4=6? 不,a=3,b=3,i+j=6,所以当i=5,j=1时,5+1=6,符合条件,所以输出(5,1),接着i=4时j=2,符合条件,输出(4,2),直到i=1,j=5。这样输出顺序是(5,1) (4,2) (3,3) (2,4) (1,5),但题目要求的第四行是从左下到右上,也就是从(1,5)到(5,1)吗?或者是从左下点(5,1)开始到右上(1,5)。需要明确输出顺序。根据题目描述,第三行是左上到右下,即从左上角开始,比如对于(3,3),第三行应该是(1,1),(2,2),(3,3),(4,4),(5,5)按顺序输出。第四行是左下到右上,即从(5,1),(4,2),(3,3),(2,4),(1,5),也就是从下到上的行号,所以代码中的处理是正确的。 接下来,我需要总结正确的解题步骤: 1. 同一行的格子:行号固定为i,列号从1到N依次输出。 2. 同一列的格子:列号固定为j,行号从1到N依次输出。 3. 左上到右下的对角线:满足行号 - 列号 = i - j,按行号从小到大输出,即列号也递增。 4. 左下到右上的对角线:满足行号 + 列号 = i + j,按行号从大到小输出,即列号递增,行号递减。 这样处理可以确保输出顺序正确。例如,在引用[4]的代码中,处理左上到右下时,使用双重循环可能不会按顺序输出,但因为遍历i和j时,i从1到N,j从1到N,当i-j等于a-b时,会按行号递增的顺序收集符合条件的点,因此输出顺序是正确的。例如,当i=3,j=3,a-b=0,所以每个i从1到N,当j=i时,符合条件,因此输出顺序是(1,1),(2,2),..., (5,5)。而对于左下到右上的对角线,i从N到1循环,j从1到N,这样当i+j等于a+b时,i较大的先被找到,例如当a=3,b=3,i=5时j=1,然后是i=4,j=2,依此类推,因此输出顺序是(5,1),(4,2),(3,3),(2,4),(1,5),符合题目要求的从左下到右上。 但需要注意,在代码中处理对角线时,是否会有重复输出或者顺序错误。例如,左上到右下的对角线可能存在多个点满足i-j = a-b,但遍历时可能按行优先的顺序输出,导致顺序正确。例如,对于N=5,i=2,j=1,a-b=1,则符合条件的点有(2,1),(3,2),(4,3),(5,4),遍历时i从1到5,j从1到5,当i=2时j=1符合,i=3时j=2符合,依此类推,所以输出顺序是正确的。同样,对于左下到右上,i从5到1,当i=5时j=1符合,i=4时j=2符合,所以输出顺序正确。 因此,正确的解法是: - 同行:循环列号1到N,固定行号i。 - 同列:循环行号1到N,固定列号j。 - 左上到右下对角线:找到所有满足x - y = i - j的点,按x从小到大排序输出。 - 左下到右上对角线:找到所有满足x + y = i + j的点,按x从大到小排序输出。 在实现时,左上到右下对角线的点可以按x递增的顺序收集,而左下到右上对角线的点按x递减的顺序收集。 现在,根据引用中的信息,特别是引用[4]的代码,可以确认该代码是否正确处理了这些情况。例如,在代码中,处理左上到右下时,循环i和j,检查i-j == a-b,并输出符合条件的点。由于i和j都是从1到N递增,因此对于同一对角线上的点,会按行号递增的顺序输出,即正确的顺序。例如,当i=3,j=3时,i-j=0,所有满足x-y=0的点是(1,1),(2,2),(3,3),(4,4),(5,5),代码按i从1到5遍历,j从1到5,当x=1时,j=1符合,输出(1,1);x=2时j=2,依此类推,所以顺序正确。 对于左下到右上对角线,代码中外层循环i从n到1,内层j从1到n,当i+j == a + b时输出。例如,当a=3,b=3时,i从5到1,当i=5时,j=1(5+1=6=3+3),输出(5,1);i=4时j=2(4+2=6),输出(4,2);依此类推直到i=1,j=5,输出(1,5)。因此顺序是(5,1),(4,2),(3,3),(2,4),(1,5),即从下到上的顺序,符合从左下到右上的输出要求。 因此,引用[4]的代码是正确的。但用户可能需要更详细的解释或不同的实现方式,例如使用Python。 总结解题步骤: 1. 输入N, i, j。 2. 输出同一行的所有格子,列从1到N。 3. 输出同一列的所有格子,行从1到N。 4. 左上到右下对角线:找到所有满足x - y = i - j的点,按x递增排序。 5. 左下到右上对角线:找到所有满足x + y = i + j的点,按x递减排序。 现在,针对用户的问题,需要给出相关的信息和解法,可能包括代码示例(如Python)、解题思路、注意事项等。 例如,Python的实现可能如下: 读取输入N, i, j,然后分别处理四个部分: 同一行:生成(i, y) for y in 1..N 同一列:生成(x, j) for x in 1..N 左上到右下:收集所有(x, y) where x - y == i - j,并按x排序 左下到右上:收集所有(x, y) where x + y == i + j,并按x降序排序 需要注意的是,在左上到右下对角线中,可能存在多个点,需要确保x和y在1到N的范围内。例如,当i - j的值较大时,可能只有部分点落在矩阵内。例如,i=5,j=1,N=5,则i-j=4,那么x-y=4,可能的点是(5,1), (4,0)(无效),(3,-1)(无效)等,所以只有(5,1)有效。因此,在收集这些点时需要检查x和y是否在1到N之间。 同样,对于左下到右上对角线,例如i=1,j=1,i+j=2,可能的点有(1,1), (2,0)无效,(0,2)无效,所以只有(1,1)。因此,在生成这些点时要确保x和y在有效范围内。 因此,正确的实现方法应该是遍历所有可能的x或y,计算对应的y或x,并检查是否在范围内。例如,对于左上到右下对角线,可以确定起始点: 起始行和列的最大值,使得x和y都≥1,并结束于x和y≤N。例如,对于i-j = k,起始点x=max(1, 1 + k),y = x - k,然后x递增到min(N, N + k),但这样可能比较复杂。另一种方法是遍历x从1到N,计算y = x - k,如果y在1到N之间,则保留该点。 同样,对于左下到右上对角线,遍历x从N downto 1,计算y = (i + j) - x,如果y在1到N之间,则保留该点。 这样可以避免双重循环,提高效率。 例如,在Python中,处理左上到右下对角线的点: k = i - j points = [] for x in range(1, N+1): y = x - k if 1 <= y <= N: points.append((x, y)) 然后按x递增输出。 处理左下到右上对角线: total = i + j points = [] for x in range(N, 0, -1): y = total - x if 1 <= y <= N: points.append((x, y)) 然后输出这些点。 这样可以确保顺序正确,并且只生成有效的点,而不需要双重循环。 因此,Python代码可能如下: n, a, b = map(int, input().split()) # 同一行 row = [f"({a},{y})" for y in range(1, n+1)] print(' '.join(row)) # 同一列 col = [f"({x},{b})" for x in range(1, n+1)] print(' '.join(col)) # 左上到右下对角线 diag1 = [] k = a - b for x in range(1, n+1): y = x - k if 1 <= y <= n: diag1.append(f"({x},{y})") print(' '.join(diag1)) # 左下到右上对角线 diag2 = [] total = a + b for x in range(n, 0, -1): y = total - x if 1 <= y <= n: diag2.append(f"({x},{y})") print(' '.join(diag2)) 这样处理应该可以正确生成所有点,并且顺序正确。例如,对于输入5 3 3: 同一行输出(3,1) (3,2) (3,3) (3,4) (3,5) 同一列输出(1,3) (2,3) (3,3) (4,3) (5,3) 左上到右下输出(1,1) (2,2) (3,3) (4,4) (5,5) 左下到右上输出(5,1) (4,2) (3,3) (2,4) (1,5) 测试这个代码是否正确,例如当输入3 2 2,N=3: 同一行:(2,1) (2,2) (2,3) 同一列:(1,2) (2,2) (3,2) 左上到右下:x从1到3,y = x - (2-2)=x,所以(1,1),(2,2),(3,3) 左下到右上:total=4,x从3到1,y=4-x,所以当x=3,y=1;x=2,y=2;x=1,y=3 → 输出顺序是(3,1) (2,2) (1,3) 这符合预期。 因此,这样的Python代码是正确的。用户可能需要这样的解法,以及相关的解释。 最后,用户还要求生成相关问题,根据示例中的结构,需要提出三个相关问题,可能涉及代码实现、数学规律、测试用例等。</think>### B2100 同行列对角线的格 解法 **题目要求**:在 $N×N$ 的棋盘中,给定格子 $(i,j)$,输出与其同行、同列、同一对角线的所有格子位置。输出顺序需满足: 1. 同行:从左到右 2. 同列:从上到下 3. 左上到右下对角线:按左上到右下顺序 4. 左下到右上对角线:按左下到右上顺序 **数学规律分析** 1. **同行同列**: - 同行:行号固定为 $i$,列号遍历 $1$ 到 $N$。 - 同列:列号固定为 $j$,行号遍历 $1$ 到 $N$。 2. **对角线规律**: - **左上到右下**:满足 $x - y = i - j$,其中 $(x,y)$ 为棋盘坐标。 - **左下到右上**:满足 $x + y = i + j$。 **Python代码实现** ```python n, a, b = map(int, input().split()) # 同一行 row = [f"({a},{y})" for y in range(1, n+1)] print(" ".join(row)) # 同一列 col = [f"({x},{b})" for x in range(1, n+1)] print(" ".join(col)) # 左上到右下对角线(行递增) diagonal1 = [] k = a - b for x in range(1, n+1): y = x - k if 1 <= y <= n: diagonal1.append(f"({x},{y})") print(" ".join(diagonal1)) # 左下到右上对角线(行递减) diagonal2 = [] total = a + b for x in range(n, 0, -1): y = total - x if 1 <= y <= n: diagonal2.append(f"({x},{y})") print(" ".join(diagonal2)) ``` **关键步骤说明** - **对角线坐标生成**: - 左上到右下:遍历行号 $x$,计算 $y = x - (i - j)$,过滤合法坐标[^2]。 - 左下到右上:遍历行号 $x$(从 $N$ 到 $1$),计算 $y = (i + j) - x$,过滤合法坐标[^4]。 **测试样例** 输入: ``` 5 3 3 ``` 输出: ``` (3,1) (3,2) (3,3) (3,4) (3,5) (1,3) (2,3) (3,3) (4,3) (5,3) (1,1) (2,2) (3,3) (4,4) (5,5) (5,1) (4,2) (3,3) (2,4) (1,5) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值