创作想法是因为像我当初大一时候想参加一些比赛但是奈何只学了c和c相关数据结构,但是对于许多竞赛的题目的题解往往都是c++或者其他面向对象的编程语言,让我们难以在c语言基础上入手这些比较复杂的题目。
创造的目的是为了帮助各位同时提高我对c语言编程的理解和锻炼个人能力,废话不多说上菜!!
1.矩阵重塑(其一)
刷新
时间限制: 1.0 秒
空间限制: 512 MiB
相关文件: 题目目录(样例文件)
题目背景
矩阵(二维)的重塑(reshape)操作是指改变矩阵的行数和列数,同时保持矩阵中元素的总数不变。
题目描述
矩阵的重塑操作可以具体定义为以下步骤:
设原矩阵为 𝑀M ,其维度为 𝑛×𝑚n ×m ,即有 𝑛n 行和 𝑚m 列。新矩阵为 𝑀′M ′,其维度为 𝑝×𝑞p ×q 。重塑操作要满足 𝑛×𝑚=𝑝×𝑞n ×m =p ×q,这保证了元素的总数不变。
- 线性化原矩阵 :按照行优先的顺序,将原矩阵 𝑀M 的元素转换成一个长度为 𝑛×𝑚n ×m 的一维数组 𝐴A 。这意味着你先读取 𝑀M 的第 00 行元素,然后是第 11 行,依此类推,直到最后一行。
- 填充新矩阵 :使用一维数组 𝐴A 中的元素按照行优先的顺序填充新矩阵 𝑀′M ′。首先填充 𝑀′M ′ 的第 00 行,直到该行有 𝑞q 个元素,然后继续填充第 11 行,直到所有 𝑝p 行都被填满。
给定原矩阵中的一个元素的位置 (𝑖,𝑗)(i ,j )(0≤𝑖<𝑛0≤i <n 且 0≤𝑗<𝑚0≤j <m ),我们可以找到这个元素在被线性化后的一维数组 𝐴A 中的位置 𝑘k (0≤𝑘<𝑛×𝑚0≤k <n ×m ),然后确定它在新矩阵 𝑀′M ′ 中的位置 (𝑖′,𝑗′)(i ′,j ′)(0≤𝑖′<𝑝0≤i ′<p 且 0≤𝑗<𝑞0≤j <q )。它们之间满足如下数学关系:𝑖×𝑚+𝑗=𝑘=𝑖′×𝑞+𝑗′i ×m +j =k =i ′×q +j′
给定 𝑛×𝑚n ×m 的矩阵 𝑀M 和目标形状 𝑝p 、𝑞q ,试将 𝑀M 重塑为 𝑝×𝑞p ×q 的矩阵 𝑀′M′。
输入格式
从标准输入读入数据。
输入共 𝑛+1n+1 行。
输入的第一行包含四个正整数 𝑛n 、𝑚m 和 𝑝p 、𝑞q。
接下来依次输入原矩阵 𝑀M 的第 00 到第 𝑛−1n −1 行,每行包含 𝑚m 个整数,按列下标从 00 到 𝑚−1m−1 的顺序依次给出。
输出格式
输出到标准输出。
输出共 𝑝p 行,每行 𝑞q 个整数,表示重塑后的矩阵 𝑀′M ′。输出格式与输入相同,即依次输出 𝑀′M ′ 的第 00 行到第 𝑝−1p −1 行;行内按列下标从 00 到 𝑞−1q−1 的顺序输出,且两个整数间仅用一个空格分隔。
样例1输入
2 3 3 2
1 2 3
4 5 6
样例1输出
1 2
3 4
5 6
样例2输入
2 2 1 4
6 6
6 6
样例2输出
6 6 6 6
子任务
全部的测试数据满足:
- 𝑛n 、𝑚m 和 𝑝p 、𝑞q 均为正整数且 𝑛×𝑚=𝑝×𝑞≤104n ×m =p ×q≤104;
- 输入矩阵中每个元素的绝对值不超过 10001000。
来自 <TUOJ>
tip:上面看不请 我在单独拿出来
主函数部分------
具体函数部分--------
然后实现功能 即可通过:
下面是完整代码:
cpp
#include<stdlib.h>
#include<stdio.h>
int** RecreatMatrix(int** a, int n, int m, int p, int q)
{
// 变量初始
int* tmp = (int*)malloc(n*m*sizeof(int));// 中间矩阵
int size = 0;//
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
tmp[size++]=a[i][j];
}
}
// 创建目标矩阵 obj
int** obj = (int**)malloc(p * sizeof(int*));
for (int i = 0; i < p; i++)
{
obj[i] = (int*)malloc(q * sizeof(int));
}
// 存放元素吧
for (int i = 0; i < n; i++)
{
free(a[i]);
}
free(a);
int x = 0;
for (int i = 0; i < p; i++)
{
for (int j = 0; j < q; j++)
{
obj[i][j] = tmp[x];
x++;
}
}
return obj;
}
int main()
{
int n = 0;
int m = 0;
int p = 0;
int q = 0;
scanf("%d %d %d %d",&n,&m,&p,&q);
int** matrix = (int**)malloc( n*sizeof(int*));
for (int i = 0;i < n; i++)
{
matrix[i] = (int*)malloc(m*sizeof(int));
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
scanf("%d", &matrix[i][j]);
}
}
// 调用函数 更改行和列
matrix = RecreatMatrix(matrix,n, m, p, q);
for (int i = 0; i < p; i++)
{
for (int j = 0; j < q; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
//确保严谨 记得销毁哦 遍历的类似思路可以拿过来
for (int i = 0; i < p; i++)
{
free(matrix[i]);
}
free(matrix);
matrix = NULL;
return 0;
}
2.重塑矩阵二----依然动态实现
时间限制: 1.0 秒
空间限制: 512 MiB
相关文件: 题目目录(样例文件)
题目背景
矩阵转置操作是将矩阵的行和列交换的过程。在转置过程中,原矩阵 𝐴A 的元素 𝑎𝑖𝑗aij 会移动到转置后的矩阵 𝐴𝑇AT 的 𝑎𝑗𝑖aji 的位置。这意味着 𝐴A 的第 𝑖i 行第 𝑗j 列的元素在 𝐴𝑇AT 中成为了第 𝑗j 行第 𝑖i 列的元素。
例如,有矩阵 𝐴A 如下:
𝐴=[𝑎𝑏𝑐𝑑𝑒𝑓]A=[adbecf]
它的转置矩阵 𝐴𝑇AT 会是:
𝐴𝑇=[𝑎𝑑𝑏𝑒𝑐𝑓]AT=abc**def
矩阵转置在线性代数中是一个基本操作,广泛应用于各种数学和工程领域。
题目描述
给定 𝑛×𝑚n×m 的矩阵 𝑀M,试编写程序支持以下查询和操作:
- 重塑操作****𝑝p**、**𝑞**q:将当前矩阵重塑为 𝑝×𝑞p×q 的形状(重塑的具体定义见上一题);
- 转置操作:将当前矩阵转置;
- 元素查询****𝑖i**、𝑗**j:查询当前矩阵第 𝑖i 行 𝑗j 列的元素(0≤𝑖<𝑛0≤i<n 且 0≤𝑗<𝑚0≤j<m)。
依次给出 𝑡t 个上述查询或操作,计算其中每个查询的结果。
输入格式
从标准输入读入数据。
输入共 𝑛+𝑡+1n+t+1 行。
输入的第一行包含三个正整数 𝑛n、𝑚m 和 𝑡t。
接下来依次输入初始矩阵 𝑀M 的第 00 到第 𝑛−1n−1 行,每行包含 𝑚m 个整数,按列下标从 00 到 𝑚−1m−1 的顺序依次给出。
接下来输入 𝑡t 行,每行包含形如 op a b 的三个整数,依次给出每个查询或操作。具体输入格式如下:
- 重塑操作:1 p q
- 转置操作:2 0 0
- 元素查询:3 i j
输出格式
输出到标准输出。
每个查询操作输出一行,仅包含一个整数表示查询结果。
样例1输入
解释
3 2 3
1 2
3 4
5 6
3 0 1
1 2 3
3 1 2
样例1输出
2
6
样例2输入
解释
3 2 5
1 2
3 4
5 6
3 1 0
2 0 0
3 1 0
1 3 2
3 1 0
样例2输出
3
2
5
初始矩阵: [123456]135246, (1,0)(1,0) 位置元素为 33;
转置后: [135246][123456], (1,0)(1,0) 位置元素为 22;
重塑后: [135246]154326, (1,0)(1,0) 位置元素为 55。
子任务
8080 的测试数据满足:
- 𝑡≤100t≤100;
全部的测试数据满足:
- 𝑡≤105t≤105 且其中转置操作的次数不超过 100100;
- 𝑛n、𝑚m 和所有重塑操作中的 𝑝p、𝑞q 均为正整数且 𝑛×𝑚=𝑝×𝑞≤104n×m=p×q≤104;
- 输入矩阵中每个元素的绝对值不超过 10001000。
提示
- 对于 𝑛×𝑚n×m 的矩阵,虽然转置和重塑操作都可以将矩阵形态变为 𝑚×𝑛m×n,但这两种操作通常会导致不同的结果。
- 评测环境仅提供各语言的标准库,特别地,不提供任何线性代数库(如 numpy、pytorch 等)。
来自 <TUOJ>
完整代码:
cpp
#include<stdlib.h>
#include<stdio.h>
int** RecreatMatrix(int** a, int n, int m, int p, int q)
{
// 变量初始
int* tmp = (int*)malloc(n*m*sizeof(int));// 中间矩阵
int size = 0;//
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
tmp[size++]=a[i][j];
}
}
// 创建目标矩阵 obj
int** obj = (int**)malloc(p * sizeof(int*));
for (int i = 0; i < p; i++)
{
obj[i] = (int*)malloc(q * sizeof(int));
}
// 存放元素吧
for (int i = 0; i < n; i++)
{
free(a[i]);
}
free(a);
int x = 0;
for (int i = 0; i < p; i++)
{
for (int j = 0; j < q; j++)
{
obj[i][j] = tmp[x];
x++;
}
}
return obj;
}
int** transpose(int** a, int n, int m)
{
int p = m;
int q = n;
int** obj = (int**)malloc(p * sizeof(int*));
for (int i = 0; i < p; i++)
{
obj[i] = (int*)malloc(q * sizeof(int));
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
obj[j][i] = a[i][j];
}
}
// 记得销毁哦
for (int i = 0; i < n; i++)
{
free(a[i]);
}
free(a);
return obj;
}
// 查询功能
int Find_x(int** a,int i, int j)
{
return a[i][j];
}
int main()
{
int n = 0;
int m = 0;
int t = 0;
scanf("%d %d %d", &n, &m, &t);
int** matrix = (int**)malloc(n * sizeof(int*));
for (int i = 0; i < n; i++)
{
matrix[i] = (int*)malloc(m * sizeof(int));
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
scanf("%d", &matrix[i][j]);
}
}
// 进入功能使用部分
while (t--)
{
int input = 0;
scanf("%d",&input);
if (input == 1)
{
int p = 0;
int q = 0;
scanf("%d %d", &p, &q);
matrix = RecreatMatrix(matrix, n, m, p, q);
n = p;
m = q;
}
else if (input == 2)
{
int p = 0;
int q = 0;
scanf("%d %d", &p, &q);
matrix = transpose(matrix, n, m);
int tmp = n;
n = m;
m = tmp;
}
else if (input == 3)
{
int i = 0;
int j = 0;
scanf("%d %d", &i, &j);
int x = Find_x(matrix,i,j);
printf("%d\n",x);
}
}
for (int i = 0; i < n; i++)
{
free(matrix[i]);
}
free(matrix);
}
3. 思路的缺陷-----以及建议
缺陷
(重塑矩阵二)简单发现代码提交之后会存在一些测试案例显示占用内存空间超出限制,这里我认为因为其中主要原因是因为:
频繁使用malloc这样的动态内存分布函数使得堆上的内存使用free后内存碎片化,使得之后没有一块连续的足够大的内存存放数据。
另一个缺陷就是我们使用malloc函数的时候都没有判空,其实严谨来说咱还是判空一下(读者自行解决咯)
建议
其实我们可以创建静态矩阵来存放数据,初始化该矩阵直接最大值即可,然后开始实现吧。
我这里仅对重塑矩阵部分进行提示,其他部分都很简单大家自己想想吧。
这里我们要用到数组指针。传递二维数组嘛
是吧更加简单明了。
好的这期就到这里非常感谢各位的支持你的小红心就是对我最大的鼓励。谢谢咯
补充: 非常抱歉,经过我后面再度调试发现我们的动态其实能过。
之所以前面内存超载了,是因为我在一个重塑矩阵函数中忘记释放一个中间载体一维数组了。
修改之后就是加一个free(tmp)即可。
至于前面的建议也可以采纳,以及对于malloc的缺陷也可以了解一下我就不删除了。谢谢咯