• CCF CSP认证 历年题目自练Day35


    题目一

    试题编号: 202305-1
    试题名称: 重复局面
    时间限制: 1.0s
    内存限制: 512.0MB
    问题描述:
    题目背景
    国际象棋在对局时,同一局面连续或间断出现3次或3次以上,可由任意一方提出和棋。

    问题描述
    国际象棋每一个局面可以用大小为 8*8的字符数组来表示,其中每一位对应棋盘上的一个格子。六种棋子王、后、车、象、马、兵分别用字母 k、q、r、b、n、p 表示,其中大写字母对应白方、小写字母对应黑方。棋盘上无棋子处用字符 * 表示。两个字符数组的每一位均相同则说明对应同一局面。
    现已按上述方式整理好了每步棋后的局面,试统计每个局面分别是第几次出现。请添加图片描述
    输入格式
    从标准输入读入数据。

    输入的第一行包含一个正整数 n,表示这盘棋总共有 n 步。

    接下来 8×n 行,依次输入第 1 到第 n 步棋后的局面。具体来说每行包含一个长度为 8 的字符串,每 8 行字符串共 64 个字符对应一个局面。

    输出格式
    输出到标准输出中。

    输出共 n 行,每行一个整数,表示该局面是第几次出现。

    样例输入

    8
    ********
    ******pk
    *****r*p
    p*pQ****
    ********
    **b*B*PP
    ****qP**
    **R***K*
    ********
    ******pk
    *****r*p
    p*pQ****
    *b******
    ****B*PP
    ****qP**
    **R***K*
    ********
    ******pk
    *****r*p
    p*p*****
    *b**Q***
    ****B*PP
    ****qP**
    **R***K*
    ******k*
    ******p*
    *****r*p
    p*p*****
    *b**Q***
    ****B*PP
    ****qP**
    **R***K*
    ******k*
    ******p*
    *****r*p
    p*pQ****
    *b******
    ****B*PP
    ****qP**
    **R***K*
    ********
    ******pk
    *****r*p
    p*pQ****
    *b******
    ****B*PP
    ****qP**
    **R***K*
    ********
    ******pk
    *****r*p
    p*p*****
    *b**Q***
    ****B*PP
    ****qP**
    **R***K*
    ********
    ******pk
    ******rp
    p*p*****
    *b**Q***
    ****B*PP
    ****qP**
    **R***K*
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    样例输出
    1
    1
    1
    1
    1
    2
    2
    1

    样例说明
    第 6、7 步后的局面分别与第 2、3 步后的局面相同。第 8 步后的局面与上图相对应。

    子任务
    输入数据满足 n≤100。

    提示
    判断重复局面仅涉及字符串比较,无需考虑国际象棋实际行棋规则。

    题目分析(个人理解)

    1. 题目挺长,但是很水,直接看样例输入输出即可知道题意,就是第一行输入n个局面,一个局面有8行8列,输出每一个局面出现的次数。
    2. 我的核心思想是这样的,将每个局面存入一个容器,当再出现相同局面的时候计数器加一(将计数器的每一步都存入列表count[]),最后遍历输出count的元素即可。
    3. 第一种方法,我选择将每个局面用temp(str型)表示,并且全部存入列表l[],(用.append()方法追加写入)每追加写入一个局面就判断一次前面是否出现过,如果出现,计数器加一,存入存放计数器的列表。
    4. 上代码!!!
    temp=''
    l=[]
    n=int(input())
    count=[1]*n
    for i in range(n):
        for j in range(8):
            temp+=input()
        l.append(temp)
        for x in range(i):
            if temp in l[x]:
                count[i]+=1
        temp=''
    for i in count:
        print(i)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 当然用字典更简单一些,用字典的keys表示每一个局面,values表示出现的次数,只需要每一步都输出然后更新字典即可。
    2. 上代码!!!
    n = int(input())
    chess = {}
    for i in range(n):
        temp = ''
        for j in range(8):
            temp += input()
        if temp not in chess:
            chess[temp] = 1
        else:
            chess[temp] += 1
        print(chess[temp])
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    题目二

    试题编号: 202305-2
    试题名称: 矩阵运算
    时间限制: 5.0s
    内存限制: 512.0MB
    问题描述:
    题目背景
    在这里插入图片描述

    是 Transformer 中注意力模块的核心算式,其中 Q、K 和 V 均是 n 行 d 列的矩阵,KT 表示矩阵 K 的转置,× 表示矩阵乘法。

    问题描述
    为了方便计算,顿顿同学将 Softmax 简化为了点乘一个大小为 n 的一维向量 W:(W⋅(Q×KT))×V
    点乘即对应位相乘,记 W(i) 为向量 W 的第 i 个元素,即将 (Q×KT) 第 i 行中的每个元素都与 W(i) 相乘。

    现给出矩阵 Q、K 和 V 和向量 W,试计算顿顿按简化的算式计算的结果。

    输入格式
    从标准输入读入数据。

    输入的第一行包含空格分隔的两个正整数 n 和 d,表示矩阵的大小。

    接下来依次输入矩阵 Q、K 和 V。每个矩阵输入 n 行,每行包含空格分隔的 d 个整数,其中第 i 行的第 j 个数对应矩阵的第 i 行、第 j 列。

    最后一行输入 n 个整数,表示向量 W。

    输出格式
    输出到标准输出中。

    输出共 n 行,每行包含空格分隔的 d 个整数,表示计算的结果。

    样例输入
    3 2
    1 2
    3 4
    5 6
    10 10
    -20 -20
    30 30
    6 5
    4 3
    2 1
    4 0 -5

    样例输出
    480 240
    0 0
    -2200 -1100

    子任务
    70 的测试数据满足:n≤100 且 d≤10;输入矩阵、向量中的元素均为整数,且绝对值均不超过 30。

    全部的测试数据满足:n≤104 且 d≤20;输入矩阵、向量中的元素均为整数,且绝对值均不超过 1000。

    提示
    请谨慎评估矩阵乘法运算后的数值范围,并使用适当数据类型存储矩阵中的整数。

    题目分析(个人理解)

    1. 读到题目先和大家复习一下线性代数的矩阵转置,很简单一句话,行变列,列变行。设矩阵m* n则转置矩阵就是n*m。要求(W⋅(Q×KT))×V,再看输入只让输入k,那么必须要实现转置的操作,有以下几种方法实现:
    2. 第一种双重循环:
    # python 双重循环
    
    arr = [[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9],
           [10, 11, 12]]
    
    arr2 = []
    # 数组的第二维维度
    for i in range(len(arr[0])):#len(arr[0])=3 
        temp = []
        # 数组的第一维维度
        for j in range(len(arr)):#len(arr)=4
            temp.append(arr[j][i])
        arr2.append(temp)
    print(arr2)
    
    '''
    # 输出结果为:
    [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
    '''
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    1. 第二种列表推导式:(和第一种没啥区别就是看上去更简洁)
    # python 列表表达式
    # 使用嵌套的列表表达式
    arr = [[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9],
           [10, 11, 12]]
    # i 为第二个维度,j 为第一个维度
    arr2 = [[arr[j][i] for j in range(len(arr))] for i in range(len(arr[0]))]
    print(arr2)
    '''
    # 输出结果为:
    [[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
    '''
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. 第三种使用python zip函数
    # python zip函数
    arr = [[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9],
           [10, 11, 12]]
    # zip(* )在这里是解压的作用
    # 将arr 看做是一个打包后的数组
    arr2 = zip(* arr)
    print(list(arr2))
    '''
    # 输出结果为:
    [(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]
    '''
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5.第四种使用numpy转置

    # 使用numpy转置
    import numpy as np
    
    arr = [[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9],
           [10, 11, 12]]
    arr = np.array(arr)
    # 这里可以三种方法达到转置的目的
    # 第一种方法
    print(arr.T)
    # 第二种方法
    print(arr.transpose())
    # 第三种方法
    print(arr.swapaxes(0, 1))
    # 上面三种方法等价
    '''
    # 三种方法的输出结果均为:
    [[ 1  4  7 10]
     [ 2  5  8 11]
     [ 3  6  9 12]]
    '''
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1. 言归正传,还是再看输入,第一行输入n,d表示矩阵n行d列,然后下面的几行依次输入矩阵Q,K,V,还是选择列表存储吧(类矩阵惯用二维列表表示)。直接用列表推导式。接着就是运算了,这道题其实只用按照逆矩阵的顺序做点乘即可,就是 W(i) 为向量 W 的第 i 个元素,即将 (Q×KT) 第 i 行中的每个元素都与 W(i) 相乘。
    2. 上代码!!!
    n, d = map(int, input().split())
    Q = [[i for i in map(int, input().split())] for j in range(n)]
    K = [[i for i in map(int, input().split())] for j in range(n)]
    V = [[i for i in map(int, input().split())] for j in range(n)]
    W = [i for i in map(int, input().split())]
    tmp = []#存放 计算: K的转置 * V
    ans = []# 计算 Q * tmp = ans
     
    # 计算 K的转置 * V = tmp
    for i in range(d):
        tmp.append([])
        #print(tmp)
        for j in range(d):
            tmp[i].append(0)#把每一步的初始计算: K的转置 * V先赋值为0
             #print(tmp)
            for k in range(n):#k表示行,注意这里只按照逆矩阵的顺序遍历运算即可n是原矩阵的行
                tmp[i][j] += K[k][i]*V[k][j]#矩阵的运算相乘再相加
     			 #print(tmp)
    # 计算 Q * tmp = ans
    for i in range(n):
        ans.append([])
        for j in range(d):
            ans[i].append(0)
            for k in range(d):
                ans[i][j] += Q[i][k]*tmp[k][j]
            ans[i][j] *= W[i]
     
    for i in range(n):
        a = []
        for j in range(d):
            a.append(ans[i][j])
        print(*a)#输出的时候空格隔开每一个元素
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    总结

    请添加图片描述

  • 相关阅读:
    Java - IO 流
    4个工作学习必备的工具,请不要错过
    算法题 — 接雨水
    Vuex 动态模块状态管理器
    python: print输出到文本文件中;赋值语句的执行流程
    富格林:采用安全出金操作方法
    数据结构——二叉树的遍历【前序、中序、后序】
    【Docker-MyCat】分库分表中间件mycat安装使用(docker版)
    【Linux】信号(2)如何阻塞、处理信号
    MySQL系列-安装配置使用说明(MAC版本)
  • 原文地址:https://blog.csdn.net/m0_63216005/article/details/133912648