CSP简单题题解 202305-1,202305-2
本次题解为 2023-05-28 第30次CCF计算机软件能力认证
题目链接🔗 202305-1 重复局面 , 🔗202305-2 矩阵运算
题解在网络上发布:方便大家获取代码,自己上手删改试试看
尽管我们知道CSP的题目有变难的趋势,笔者也亲身体会,即对于第一问的暴力解 速度越来越慢,第二问需要一些“巧思”。但最近2023年5月的这一场,两个题目几乎没有考任何数据结构知识,都是完全可以拿到100分的,在此处给一定的大家信心。
202305-1 重复局面
- 使用Cpp来处理字符串,并没有套用很复杂的STL,甚至没有出现“string”字样
- 不会动态分配空间(malloc、new)? 没关系,写死ta,第一问不会卡
- 按照你的思路 像完成作业那样,去写出来就好
#include<iostream>
using namespace std;
const int MAX = 800;
char table[MAX][8];
int t[MAX] = {0};
int main()
{
int flag1,flag2;
int n = 0;
int num = 1;
cin>>n;
for(int time = 0; time<n; time++){
for(int i = 0; i<8; i++){
for(int j = 0; j<8; j++){
cin>>table[time*8 + i][j];
}
}
num = 1;
flag1 = 0; flag2 = 0;
for(int last = time-1; last>-1; last--){ //从相邻的上一个棋盘开始,往前找
flag1 = 0; //整体棋盘的 重复标记
for(int i = 0; i<8; i++){
flag2 = 0; //某行上的 重复标记
for(int j = 0; j<8; j++){
if(table[last*8 + i][j] == table[time*8 + i][j]){
flag2++;
}
else break; //否则的话已经不用往后比, 此处没有降低复杂度
}
if(flag2 == 8)flag1++;
else break;
}
if(flag1 == 8){
num = t[last] + 1;
break;
}
}
t[time] = num;
cout<<num<<endl;
}
}
202305-2 矩阵计算
第一想法:暴力,和第一问思路不变
- 完全不应用任何的“算法”,暴力地解题,顺着你的思路解题
- Cpp中动态地分配空间new,其实不会也没关系:此处写死大概率也可以过
#include<iostream>
using namespace std;
long long* mat_mul(long long *matA, long long *matB, int row_A, int col_A, int col_B)
{
long long *result = NULL;
result = new long long[row_A * col_B];
long long temp = 0;
for(int i = 0; i<row_A; i++){
for(int j = 0; j<col_B; j++){
temp = 0;
for(int k = 0; k<col_A; k++){
temp += matA[i*col_A + k]*matB[k*col_B + j];
}
result[i*col_B + j] = temp;
}
}
return result;
}
long long* dot_product(long long *mat, long long *vec, int row, int col)
{
long long *result = NULL;
result = new long long[row * col];
for(int i = 0; i<row; i++){
for(int j = 0; j<col; j++){
result[i*col + j] = mat[i*col +j]*vec[i];
}
}
return result;
}
long long* trans(long long *mat, int row, int col)
{
long long *result = NULL;
result = new long long[row * col];
for(int i = 0; i<row; i++){
for(int j = 0; j<col; j++){
result[j*row + i] = mat[i*col +j];
}
}
return result;
}
void print_mat(long long *mat, int row, int col )
{
// cout<<"result mat is: "<<endl;
for(int i = 0; i<row; i++){
for(int j = 0; j<col; j++){
if(j != col){
cout<<mat[i* col +j]<<" ";
}
else
cout<<mat[i* col +j];
}
cout<<endl;
}
}
int main()
{
int n = 0;
int d = 0;
cin>>n>>d;
long long *matQ = NULL;
long long *matK = NULL;
long long *matKT = NULL;
long long *matV = NULL;
long long *vecW = NULL;
long long *mid1 = NULL; // n * n
long long *mid2 = NULL; // n * n
long long *result = NULL; // n * d
matQ = new long long[n*d];
matK = new long long[n*d];
matKT = new long long[n*d];
matV = new long long[n*d];
vecW = new long long[n];
mid1 = new long long[n*n];
mid2 = new long long[n*n];
result = new long long[n*d];
for(int i = 0; i<n; i++){
for(int j = 0; j<d; j++){
cin>>matQ[i*d + j]; }}
for(int i = 0; i<n; i++){
for(int j = 0; j<d; j++){
cin>>matK[i*d + j]; }}
for(int i = 0; i<n; i++){
for(int j = 0; j<d; j++){
cin>>matV[i*d + j]; }}
for(int i = 0; i<n; i++){
cin>>vecW[i]; }
matKT = trans(matK, n, d);
mid1 = mat_mul(matQ, matKT, n, d, n);
// print_mat(mid1, n, n);
mid2 = dot_product(mid1, vecW, n, n);
// print_mat(mid2, n, n);
result = mat_mul(mid2, matV, n, n, d);
print_mat(result, n, d);
delete []matV;
delete []matK;
delete []matQ;
delete []matKT;
delete []mid1;
delete []mid2;
delete []result;
return 0;
}
粗暴地尝试,不对劲 — “巧思”
- 提示:谨慎评估矩阵乘法运算后的数值范围,并使用适当数据类型存储矩阵中的整数(long long int)
- 把算子进行了“融合(Fusion)”,其实复杂度没有变 仍然是 O ( n 3 ) O(n^3) O(n3),但就差这一点
#include<iostream>
using namespace std;
void print_mat(long long *mat, int row, int col )
{
// cout<<"result mat is: "<<endl;
for(int i = 0; i<row; i++){
for(int j = 0; j<col; j++){
if(j != col){
cout<<mat[i* col +j]<<" ";
}
else
cout<<mat[i* col +j];
}
cout<<endl;
}
}
int main()
{
int n = 0;
int d = 0;
cin>>n>>d;
long long *matQ = NULL;
long long *matK = NULL;
long long *matV = NULL;
long long *vecW = NULL;
long long *result = NULL; // n * d
matQ = new long long[n*d];
matK = new long long[n*d];
matV = new long long[n*d];
vecW = new long long[n];
result = new long long[n*d];
long long sum = 0;
for(int i = 0; i<n; i++){
for(int j = 0; j<d; j++){
cin>>matQ[i*d + j]; }}
for(int i = 0; i<n; i++){
for(int j = 0; j<d; j++){
cin>>matK[i*d + j]; }}
for(int i = 0; i<n; i++){
for(int j = 0; j<d; j++){
cin>>matV[i*d + j]; }}
for(int i = 0; i<n; i++){
cin>>vecW[i]; }
for(int i = 0; i<n*d; i++){
result[i] = 0; //important !
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
sum = 0;
for (int k = 0; k < d; ++k) {
sum += matQ[i*d + k] * matK[j*d + k]; //Q * K^T (n*n)
}
sum *= vecW[i]; // dot product (element-wise)
for (int l = 0; l < d; ++l) {
result[i*d + l] += sum * matV[j*d + l]; // W·(Q * K^T) * V (n*d)
}
}
}
print_mat(result, n, d);
delete []matV;
delete []matK;
delete []matQ;
delete []vecW;
delete []result;
return 0;
}