1.题目详情
2.矩阵运算的一些性质(在本题中用到的)
(1)乘法结合律,A(BC)=(AB)C
(2)两个矩阵相乘时要满足第一个矩阵的列数等于第二个矩阵的行数。例如:A(m×n) × B(n×p)=C(m×p)
(3)矩阵的转置就是将原来的行变为列,原来的列变为行。
3.思路
(1)在CSP题中要特别注意题目中的提示语句:请谨慎评估矩阵乘法运算后的数值范围,并使用适当数据类型存储矩阵中的整数。往往提示语句决定了你是否能够得到满分。通过提示的这句话可以得出:矩阵乘法运算后的数值范围应该用long这种数据类型,并且在声明矩阵的大小时也应该遵循最大空间利用率的法则。
(2)观察运算的式子不难发现,向量W对矩阵的点乘本质上相当于是一种数乘,这个操作并不会对原有定义矩阵时声明的long类型造成内存溢出等情况。所以可以直接观察后面的两次乘法操作。
(3)若Q先和K矩阵的转置相乘,那么我们需要定义一个大小为n×n的二维数组,然后再乘矩阵V。还需定义一个大小为n×d的二维数组用来存放结果值。但是如果K矩阵的转置先和矩阵V相乘,则只需要定义一个d×d大小的数组。最后Q和这个数组相乘,定义一个n×d大小的二维数组用来存放结果值。
(4)由于题目中的n数量级要远远高于d,所以可以明显看出第二种的顺序要比第一种更加节省空间。所以我们选择第二种方式即可。
Java(100分)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int d = sc.nextInt();
int[][] Q = new int[n][d];
int[][] K = new int[n][d];
int[][] V = new int[n][d];
int[] W = new int[n];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < n; j++) {
for (int k = 0; k < d; k++) {
if(i == 0){
Q[j][k] = sc.nextInt();
}else if(i == 1){
K[j][k] = sc.nextInt();
}else {
V[j][k] = sc.nextInt();
}
}
}
}
for (int i = 0; i < n; i++) {
W[i] = sc.nextInt();
}
long[][] re1 = new long[d][d];
for (int i = 0; i < d; i++) {
for (int j = 0; j < d; j++) {
for (int k = 0; k < n; k++) {
re1[i][j] += (long) V[k][j] * K[k][i];
}
}
}
long[][] re2 = new long[n][d];
for (int i = 0; i < n; i++) {
for (int j = 0; j < d; j++) {
for (int k = 0; k < d; k++) {
re2[i][j] += (long)Q[i][k]*re1[k][j];
}
//这里的向量W其中的第i个值就要和矩阵中的第i行所有元素进行数乘运算。
re2[i][j]*=W[i];
System.out.print(re2[i][j] + " ");
}
System.out.println();
}
}
}