CSDN周赛第30期题目解析(天然气定单、小艺读书、买苹果、圆桌)

75 篇文章 0 订阅

CSDN周赛第30期,我应试成绩“0”分。试着对天然气定单、小艺读书、买苹果🍎、圆桌四个题目,完成算法解析。


(本文获得CSDN质量评分【91】)

【学习的细节是欢悦的历程】


  自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
            —— 华罗庚


等风来,不如追风去……


CSDN周赛第30期,成绩“0”分
我的零分周赛
(天然气定单、小艺读书、买苹果🍎、圆桌)


本文质量分:

91
本文地址: https://blog.csdn.net/m0_57158496/article/details/129162023

CSDN质量分查询入口:http://www.csdn.net/qc


目 录


◆我的零分周赛


  CSDN第30期周赛,四个题目看起来都不难,算法感觉都会,费劲的一道道题目作答,写出来的Python3代码却是没有一题通关。😭😭
  这即是基础不牢,地动山摇”,“不写都晓得,一写啥也不明白的真实写照啊。
  偷偷录下四个题目,试着解答,以饷“伪卷”之心意;作此笔记,以警奋进……


1、天然气订单


题目 1/4 (25 分)
题目名称:天然气订单
时间限制:1000ms内存限制:256M

1.1 题目描述

  天然气运输成本昂贵,危险性高,为了节省运输成本,提倡绿色环保,需要尽可能的优化订单配送,比如相同地区的天然气订单可以一次性配送。 现需要向多个地区运输天然气。但是同一个地区可能有多个订单需求。当前仅只知道某些成对的订单是同一个地区的,同一个地区的天然气需要尽可能一次性配送从而降低运输成本,所以需要尽可能的将同一个地区的订单放在一起。订单的编号是1到n。

输入描述:
  输入第一行是两个正整数n,m,表示订单的数量和已知的关系数量。(1<=n,m<=10000) 接下来有m行,每行两个正整数a和b,表示a号订单和b号订单属于同一个地区(1<=a,b<=n);

输出描述:
  输出第一行包含一个整数x,表示这些订单共来自x个不同的地区。接下来的输出包含x行,每行表示输出若干个订单编号,表示这些订单属于同一个地区,按照订单编号升序输出。优先输出最小的订单编号较小的地区

示例

输入
7 6
1 2
2 2
3 2
4 5
5 4
6 7

输出
3
1 2 3
4 5
6 7

提示


1.2 应考代码


应考答题截屏图
在这里插入图片描述



  我参赛时的代码,虽然成功运行了但却没有通过全部测试用例。经过查验推敲,才发现算法逻辑“没问题”,但代码有“问题”

  代码逻辑:输入字符后面的六行每行前一个整数表示定单号,后一个表示定单区域(理清代码,得到输出后,才发现曲“解”题意了),用字典收集、统计定单区域,相同区域定单放一起。输出统计的区域总数及各区域定单详情。



    def solution(self, n, m, vector):
        result = None

        # TODO: 请在此编写代码
        place = {}

        for i in range(m):
            tem = vector[i]
            lis = place.get(tem[1], [])
            lis.append(tem[0])
            place[tem[1]] = lis

        #print(place) 调试用语句。
        result = [str(len(place))]
        lis = list(place.keys())
        lis.sort()

        for i in lis:
            result.append(' '.join(map(str, place.get(i))))

        #input(result) 调试用语句。
        return result

代码运行效果截图
在这里插入图片描述


  这?!😣
  与“示例”输出有异啊?!回看“题目描述”,“输入第一行是两个正整数n,m,表示订单的数量和已知的关系数量”、“接下来有m行,每行两个正整数a和b,表示a号订单和b号订单属于同一个地区”,a、b是相同地域的定单号,后六行是已知定单地域的“关系数组”。



  修正后的算法逻辑:遍历所有定单关系数组,把有相同定单号的关系数组中的定单号,归并在一块儿。最后输出“块儿”总数及每个“块儿”详情(每个一行)
  代码实现,取出第一组关系数组,放入result列表,遍历vector与之比对,有相同地域定单,追加入当前关系数组,无则将当前关系数组append到result列表;依次遍历,完成所有比对,sum(result )获取统计“定单区域捆绑”总数;按输出格式要求输出区域总数及详情。


    def solution(self, n, m, vector):
        result = None

        # TODO: 请在此编写代码
        result = [vector.pop(0)] # 取出第一组关系数据放入结果列表。

        for i in vector: # 遍历剩下的关系数据组。
            #print('out:', result) # 调试用语句。
            a, b = i
            flag = True

            for j in result: # 比对并收集相同地域定单。

                if a in j or b in j:
                    j.extend(i)
                    flag = False
                    break

            if flag:
                result.append(i) # 结果列表无相同地域,则追加。

        result = list(map(set, result)) # 集合去除重复收集的相同定单号。
        result = [' '.join(map(str, i)) for i in result] # 字符化转存输出数据。
        result = [str(len(result))] + result # 插入输出定单区域总数。
        #input(result) # 调试用语句。
        return result

理正题意,修改算法,。得出了正确输出。
(代码运行效果截屏)
在这里插入图片描述


1.3 优化代码


1.3.1 算法优化


  将“比对统计”工作,封装成函数place,比设置flag开关,解题思路更明晰,代码更易于理解。



    def solution(self, n, m, vector):
        result = None

        # TODO: 请在此编写代码

        def place(a, b):
            ''' 收集相同地区定单 '''

            for i in result:
                if a in i or b in i:
                    if a not in i:
                        i.append(a)
                    elif b not in i:
                        i.append(b)
                    return

            return True
        
        result = []
        
        for i in vector:
            ''' 遍历地区关系列表 '''
            a, b = i

            if place(a, b):
                result.append(i)

        result = [' '.join(map(str, i)) for i in result]
        #input(result) # 调试用语句。
        return [str(len(result))] + result


1.3.2 输出代码优化

第一行和后六行,都可以用一行代码来写。


    arr_temp = [int(item) for item in input().strip().split()]
    n = int(arr_temp[0])
    m = int(arr_temp[1])
    vector = []

    for i in range(m):
        vector.append([int(item) for item in input().strip().split()])

第一行,用map()函数接收键盘录入,直接为n、m赋值;后六行用列表解析+map()函数接收键盘录入并转换str-int。

    
    n, m = map(int, input().strip().split())
    #input([n, m]) # 调试用语句。
    vector = [list(map(int, (input().strip().split()))) for i in range(m)]


回页目录

2、小艺读书


题目 2/4 (25 分)
题目名称:小艺读书
时间限制:1000ms内存限制:256M

2.1 题目描述

  书是人类进步的阶梯。
  小艺每周因为工作的原因会选择性的每天多读几页或者少读几页。
  小艺想知道一本n页的书她会在周几读完。

输入描述:
第一行输入n(1<=n<=1000);
第二行输入7个整数,分别表示周一~周日的读书页数p(0<=p<=1000)。(不考虑7个整数都为0的情况)

输出描述:
输出答案。(1-7)

示例

输入
100
15 20 20 15 10 30 45

输出
6

提示

2.2 应考代码


应考答题截屏图
在这里插入图片描述


  参赛答题代码,按算法逻辑“遍历累加每计划看书页数,等于或者超过书页数n,书即看完。输出此时列表的下标+1,即是周几”,写出代码:


    def solution(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for num in pages:
            n -= num

            if n <= 0:
                result = num+1
                print(result)
                break

        return result

在这里插入图片描述

  输出的却是31!!🤔
  仔细观察,该输出下标+1,却输出了“元素+1”😂


            if n <= 0:
                result = num+1
                print(result)
                break

  所以,输出不对😂😂


修改错误代码行


            if n <= 0:
                result = pages.index(num)+1
                #print(result) #调试用语句。
                break

得到了正确输出
在这里插入图片描述


2.3 优化代码


2.3.1 获取下标算法欠妥

  list.index(x)函数是返回list中第一个“x”元素的下标,如果处理列表中有相同元素,就仅返回第一次出现位置的下标。打印出每次遍历的下标,就可以清楚的看到,两个“20”、两个“15”的下标,是一样的。😂这会导致,在改变要读书的页数,可能不会得到“正确”输出。


    # list.index()法
    def solution(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for num in pages:
            print(f"\n星期{pages.index(num)+1},计划看{num}页")
            n -= num

            if n <= 0:
                result = pages.index(num)+1
                #print(result) #调试用语句。
                break

        return result

在这里插入图片描述


  可以用设置计数器或者枚举函数enmerate()同时遍历下标及元素,来修正这样子这个“bug”。

计数器设置


    # 加计数器法
    def solution(self, n, pages):
        result = None
        # TODO: 请在此编写代码
        k = 0 # 计数器初始化。

        for num in pages:
            k += 1
            #print(f"\n星期{k},计划看{num}页")
            n -= num

            if n <= 0:
                result = k
                #print(result) #调试用语句。
                break

        return result

在这里插入图片描述

enmerate()枚举函数遍历


    # enumerate()枚举函数法
    def solution5(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for index,num in enumerate(pages):
            #print(f"\n星期{index+1},计划看{num}页")
            n -= num

            if n <= 0:
                result = index+1
                #print(result) #调试用语句。
                break

        return result

2.3.2 优化多余语句

    # 代码优化
    def solution3(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for index,num in enumerate(pages):
            #print(f"\n星期{index+1},计划看{num}页")
            n -= num

            if n <= 0:
                return index+1

  当达成“看完”书的条件,豆可以直接return index+1了,不用退出循环再return 。

2.3.3 题目暗藏玄机


看过大佬的赛题解析,才明白:

  • 题目没说明是周日还是周一是每周的“第一天”
    我们一般都是用周一作为每周“第一”,解题依此默认。

  • 书本太厚,一周读不完
    遇到这种情况的输入,我的代码就只会输出默认的None了。🤪所以,在接收键盘输入后,立马来一条带“%”的代码语句,对书总页数用周计划阅读页数取余。


    n = n % sum(pages) # 书总页数对一周计划阅读总量取模。



回页目录

3、买苹果


题目 3/4 (25 分)
题目名称:买苹果
时间限制:1000ms内存限制:256M

3.1 题目描述

  小易去附近的商店买苹果,奸诈的商贩使用了捆绑交易,只提供6个每袋和8个每袋的包装(包装不可拆分)。 可是小易现在只想购买恰好n个苹果,小易想购买尽量少的袋数方便携带。如果不能购买恰好n个苹果,小易将不会购买。

输入描述:

  输入一个整数n,表示小易想购买n(1 ≤ n ≤ 100)个苹果

输出描述:
  输出一个整数表示最少需要购买的袋数,如果不能买恰好n个苹果则输出-1

示例

输入
20

输出
3

提示


3.2 应考代码


应考答题截屏图
在这里插入图片描述


    def solution(self, n):
        result = None
        # TODO: 请在此编写代码

        for i in range(n//8+1):
            if (n-i*8)%6 == 0:
                b = (n-i*8)//6
                print(f"\n{i}×8={i*8},{b}×6={b*6}\n")
                return i+b

        return -1

在这里插入图片描述

  看似得到了正解,其实不然。当把输入换过,就不一定是正解了。这说明,代码承载的算法是偏颇的,是不正解的。这是由于我对Python代码实现算法的不“能”造成的。
  这道题目其实算法挺简单的,穷举所有购买方案,从中找出最少购买包数就好。

  经过多翻调试,终于捋清代码逻辑😄


class Solution:

    def __init__(self) -> None:
        pass

    def solution(self, n):
        result = None
        # TODO: 请在此编写代码

        def work(result = n): # 令购买袋数初值为n。
            ''' 穷举所有方案,遴选最少袋数 '''
            k = 0 # 方案数初值。

            for i in range(n//8+1): # 用8个一袋遍历,循环次数略少。
                                
                if (n-i*8)%6 == 0:
                    k += 1 # 方案计数。
                    b = (n-i*8)//6
                    
                    if result > b+i:
                        result = b+i
                    
                    print(f"\n{k}. {i}+{b}={i+b} (8×{i}={i*8},6×{b}×6={b*6})")

            return result

        result = work()

        if result == n:
            return -1
        else:
            return result


if __name__ == "__main__":
    n = int(input('\n输入购买苹果个数:').strip())
    sol = Solution()
    print(f"{'':~^50}\n所有购买组合方案:")
    result = sol.solution(n)
    print(f"\n{'':~^50}\n输出购买总袋数:{result}")

示例截屏图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  通过多个输入数据验证,无疑代码对算法的解读是正确的。我打印出了每个购买方案的详情,已经算是“一目了然”,豆不用我画蛇添足的再解说了。🤪


3.3 优化代码


  以我当前水准,这花时间捋顺的代码,已“算”最优,我不能再优化的了。


回页目录

4、圆桌


题目 4/4 (25 分)
题目名称:圆桌
时间限制:1000ms内存限制:256M

4.1 题目描述

  有N个客人与足够多张的圆桌。主人安排每位客人坐在一个圆桌边,但是每位客人希望自己左右边上分别有一些空座位,不然会觉得害羞。注意,如果一个客人所在的圆桌只有他一个人,那么他左边的空座位数量就是他右边的空座位数量。 试问主人需要准备多少个座位,才能让每个客人舒适的坐下。

输入描述:
  第一行输入一个整数N,(1<=N<=10000),代表客人的数量 接下来N行,每行两个整数li与ri,(1<=i<=N,1<=li<=ri<=1000000000) 代表第i位客人希望左边有li个空座位,右边有ri个空座位。

输出描述:
  输出一个整数,代表主人需要准备的最少座位数量。

示例1
输入
3
1 1
1 1
1 1

输出
6

示例2
输入
4
1 2
2 1
3 5
5 3

输出
15

提示
【样例解释】3个人围成一桌,每人左右各一个空位置,一共3个空座位。一个共需要3+3=6座位。


4.2 应考代码


应考答题截屏图
在这里插入图片描述

  应试时,连题目都没有理清,所以写出了“不知所云”的代码。

  “注意,如果一个客人所在的圆桌只有他一个人,那么他左边的空座位数量就是他右边的空座位数量。”题目描述中的这句话就是说,任何空座需求的客人,都可以可以单独坐一桌的,因为其左右空座会连在一起,不会违背“他左边的空座位数量就是他右边的空座位数量”。但如不拼桌则会算多空座,如示例2,分4桌坐,就应该是3 3 6 6,共需18把椅子。

  我觉得,这个题目,还是另起一篇学习笔记讲述解析解题算法,要好一些。


回页目录

5、本篇完整源码

(源码较长,点此跳过源码)

#!/sur/bin/nve python 
# coding: utf-8


''' CSDN周赛第30期 '''


# 01 天然气定单

class Solution:

    def __init__(self) -> None:
        pass

    def solution(self, n, m, vector):
        result = None

        # TODO: 请在此编写代码
        place = {}

        for i in range(m):
            tem = vector[i]
            lis = place.get(tem[1], [])
            lis.append(tem[0])
            place[tem[1]] = lis

        #print(place) 调试用语句。
        result = [str(len(place))]
        lis = list(place.keys())
        lis.sort()

        for i in lis:
            result.append(' '.join(map(str, place.get(i))))

        #input(result) 调试用语句。
        return result


    def solution(self, n, m, vector):
        result = None

        # TODO: 请在此编写代码
        result = [vector.pop(0)] # 取出第一组关系数据放入结果列表。

        for i in vector: # 遍历剩下的关系数据组。
            #print('out:', result) # 调试用语句。
            a, b = i
            flag = True

            for j in result: # 比对并收集相同地域定单。

                if a in j or b in j:
                    j.extend(i)
                    flag = False
                    break

            if flag:
                result.append(i) # 结果列表无相同地域,则追加。

        result = list(map(set, result)) # 集合去除重复收集的相同定单号。
        result = [' '.join(map(str, i)) for i in result] # 字符化转存输出数据。
        result = [str(len(result))] + result # 插入输出定单区域总数。
        #input(result) # 调试用语句。
        return result


    def solution8(self, n, m, vector):
        result = None

        # TODO: 请在此编写代码

        def place(a, b):
            ''' 收集相同地区定单 '''

            for i in result:
                if a in i or b in i:
                    if a not in i:
                        i.append(a)
                    elif b not in i:
                        i.append(b)
                    return

            return True
        
        result = []
        
        for i in vector:
            ''' 遍历地区关系列表 '''
            a, b = i

            if place(a, b):
                result.append(i)

        result = [' '.join(map(str, i)) for i in result]
        #input(result) # 调试用语句。
        return [str(len(result))] + result



if __name__ == "__main__":
    print('\n输入:')
    '''改写这段代码,让提示输入“更友好”。
    arr_temp = [int(item) for item in input().strip().split()]
    n = int(arr_temp[0])
    m = int(arr_temp[1])
    vector = []

    for i in range(m):
        vector.append([int(item) for item in input().strip().split()])
    '''
    
    n, m = map(int, input().strip().split())
    #input([n, m]) # 调试用语句。
    vector = [list(map(int, (input().strip().split()))) for i in range(m)]
    #n, m, vector = 7, 6, [[1, 2], [2, 2], [3, 2], [4, 5], [5, 4], [6, 7]] # 调试用语句。
    #input(f"{n}, {m}, {vector}") # 调试用语句。
    sol = Solution()
    result = sol.solution(n, m, vector)
    print('\n输出:') 
    print("\n".join(result))


input() 


# 02 小艺读书

class Solution:

    def __init__(self) -> None:
        pass

    def solution(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for num in pages:
            n -= num

            if n <= 0:
                result = num+1
                print(result)
                break

        return result


    # list.index()法
    def solution(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for num in pages:
            print(f"\n星期{pages.index(num)+1},计划看{num}页")
            n -= num

            if n <= 0:
                result = pages.index(num)+1
                #print(result) #调试用语句。
                break

        return result

    # 加计数器法
    def solution(self, n, pages):
        result = None
        # TODO: 请在此编写代码
        k = 0 # 计数器初始化。

        for num in pages:
            k += 1
            print(f"\n星期{k},计划看{num}页")
            n -= num

            if n <= 0:
                result = k
                #print(result) #调试用语句。
                break

        return result


    # enumerate()枚举函数法
    def solution5(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for index,num in enumerate(pages):
            #print(f"\n星期{index+1},计划看{num}页")
            n -= num

            if n <= 0:
                result = index+1
                #print(result) #调试用语句。
                break

        return result


    # 代码优化
    def solution(self, n, pages):
        result = None
        # TODO: 请在此编写代码

        for index,num in enumerate(pages):
            #print(f"\n星期{index+1},计划看{num}页")
            n -= num

            if n <= 0:
                return index+1


if __name__ == "__main__":
    print('\n输入:')
    #n = int(input().strip())
    #pages = [int(item) for item in input().strip().split()]
    n, pages = 100, [15, 20, 20, 15, 10, 30, 45]
    print(f"{n}\n{' '.join(map(str, pages))}\n")
    n = n % sum(pages) # 书总页数对一周计划阅读总量取模。
    sol = Solution()
    result = sol.solution(n, pages)
    print(f"\n输出:\n{result}")


input()


#03 买苹果
class Solution:

    def __init__(self) -> None:
        pass

    def solution(self, n):
        result = None
        # TODO: 请在此编写代码

        def work(result = n): # 令购买袋数初值为n。
            ''' 穷举所有方案,遴选最少袋数 '''
            k = 0 # 方案数初值。

            for i in range(n//8+1): # 用8个一袋遍历,循环次数略少。
                                
                if (n-i*8)%6 == 0:
                    k += 1 # 方案计数。
                    b = (n-i*8)//6
                    
                    if result > b+i:
                        result = b+i
                    
                    print(f"\n{k}. {i}+{b}={i+b} (8×{i}={i*8},6×{b}×6={b*6})")

            return result

        result = work()

        if result == n:
            return -1
        else:
            return result


if __name__ == "__main__":
    n = int(input('\n输入购买苹果个数:').strip())
    sol = Solution()
    print(f"{'':~^50}\n所有购买组合方案:")
    result = sol.solution(n)
    print(f"\n{'':~^50}\n输出购买总袋数:{result}")


input() 

 
#04 圆桌


def table(n, lis):
    ''' 计算桌数和需准备座位数 '''
    result = 0 # 需求空座位数初值。
    temp = [] # 相同空座需求客人统计列表初始化。
    
    
    while lis: # 统计同桌客人。
        tem = [lis[0]]
        l, r = lis[0]
        lis.pop(0)
        
        for i in lis[:]: # 这里一定要遍历用切片复制lis[:],因为lis可能“动态”变短。
            li, ri = i

            if li == r:                
                tem.append(i)
                lis.remove(i)
                r = ri

        while len(tem) > 1:
            l_start, ri = tem[-1][1], tem[0][0]
            if ri == l_start:
                break # 客人空座链能首尾相接围坐一桌,退出检验循环。
            else: # 否则,把最后一位客人退回客人空座信息列表lis。
                lis.append(tem.pop())

        temp.append(tem)

    print(f"\n{'':~^50}\n客人分桌信息数组:\n{temp}\n{'':~^50}")
    
    for i in temp: # 遍历客人分桌列表,计算同桌客人共用空座。

        if len(i) == 1:
            result += max(i[0])
            continue

        result += sum(j[1] for j in i)

    return len(temp), result + n # 返回客人桌数和需准备的椅子总数(空座数+客人数)。


if __name__ == '__main__':
    n = int(input('\n输入:\n'))
    lis = [tuple(map(int, input().strip().split())) for i in range(n)]
    t = table(n, lis)
    print(f"\n输出:\n{t[1]}\n\n客人需坐{t[0]}桌,共要准备{t[1]}个椅子。")


回页首

__上一篇:__ ChatGPT初体验(ChatGPT国内镜像站试用,聊天、Python代码生成)
__下一篇:__ 

我的HOT博:

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包

    打赏作者

    梦幻精灵_cq

    你的鼓励将是我创作的最大动力

    ¥1 ¥2 ¥4 ¥6 ¥10 ¥20
    扫码支付:¥1
    获取中
    扫码支付

    您的余额不足,请更换扫码支付或充值

    打赏作者

    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

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

    余额充值