• 天天快乐编程杯中学生信奥联赛(202002) 题解(Python版)


    此博客原文地址:https://www.cnblogs.com/BobHuang/p/12312134.html

    1.6172: Alice视察

    本题目比较困难,我们将信息传递出去,而且要满足最短的,那么其实只需要n-1条边,是一棵无向树。在数据结构中有“最小生成树”,有两个算法,分别是Kruskal(加边)及Prime(加点)。这个题目数据量比较小,不卡算法,你可以实现任一算法AC。题解所用的是Kruskal。
    这个算法的思想可以这样理解,我将所有的边按照权值进行排序,我必定会先选择最小的边,怎么确定这个边可以用另一数据结构“并查集”,他也是一棵无向树。没有连接这条边肯定要选,所以也有点贪心的意思。最后n-1条边将n个点连接起来就是最小的。

    #并查集
    class UDFS:
    
        def __init__(self, n):
            self.n = n
            self.parents = [i for i in range(n)]
            self.ranks = [0 for i in range(n)]
     
        def Find(self, a):
            if a == self.parents[a]:
                return a
            
            self.parents[a] = self.Find(self.parents[a])
            return self.parents[a]
     
        def join(self, a, b):
            parent_a = self.Find(a)
            parent_b = self.Find(b)
            if(parent_a!=parent_b):
                self.parents[parent_a] = parent_b
                return 1
            return 0
    
    
    n_nodes, n_edges = map(int, input().split())
    edges = list()
    for i in range(n_edges):
            a, b, w = map(int, input().split())
            edges.append((w, a , b))
    
    dsu = UDFS(n_nodes+1) 
    edges.sort()
    tot = 1
    mi = 0
    
    for edge in edges:
      if(dsu.join(edge[1],edge[2])!=0):
          mi = mi + edge[0]
          tot = tot + 1
          if(tot==n_nodes):
            break
    print (mi)
    

    2.6178: Alice运快递

    第一问是一个很经典的01背包问题,一个物品可以选一次,所以我们这时候的状态是从前一个状态过来的。当前物品是否可以放下,是不是更大都是需要我们考虑的。01背包只能选一次,我们可以优化只用一维dp数组,第二重循环需要倒着进行。
    第二问是个很简单的贪心问题,我们可以选择体积最小的货物装上。

    while True:
        try:
            m,n=map(int,input().split())
            w=[0]*n
            c=[0]*n
            for i in range(n):
                w[i],c[i]=map(int,input().split())
            dp=[0]*(m+5)
            for i in range (n):
                for j in range(m, w[i]-1,-1):
                    dp[j]=max(dp[j],dp[j-w[i]]+c[i])
            w.sort()
            ans = 0
            sum = 0
            for i in range (n):
                if sum+w[i] <= m :
                     sum += w[i]
                     ans = ans+1
                else:
                     break
            print(dp[m],ans)
        except EOFError:
            break
    

    3.6173: 相同行程查询

    这个题目有些困难,我们需要知道这个人的车次,之后我们会找到人然后对应到这个车次。最终我们要查询的是车次,当然我们可以进行排序之后二分。不过这个题目有个更好用的东西,叫dict字典。<key,value>也叫键值对,前面可以把放键,可以理解为就是一个下标,后面放值。所以就是人和车次的dict以及车次和人数的dict。这个“None”不能强转为数字,自己可以写个函数处理下。

    def xstr(s):
        if s is None:
            return 0
        return int(s)
    n=int(input())
    peo=dict()
    for i in range(n):
        data=list(map(str,input().split()))
        peo.update(dict([(k,data[0]) for k in data[2:]]))
    m=int(input())
    trains=dict()
    peos=list(map(str,input().split()))
    for i in range(m):
        t=xstr((trains.get(peo.get(peos[i]))))+1
        trains.update({peo.get(peos[i]):t})
    q=int(input())
    for i in range(q):
        train=input()
        print(xstr((trains.get(train))))
    

    4.6177: Alice玩汉诺

    这个题目我们可以采用常规做法,就是我们递归的时候可以统计移动次数。
    当然也可以找到递推式,数量级大的情况就必须使用递推式了。
    A->B=(上一次)A->C->B
    B->C=(上一次)B->A->C
    C->A=(上一次)C->B->A
    我这里用了递归写法,我们可以设置变量去统计他们,在每次移动的时候去统计。

    ans = []
    def cal(a,c):
        if(a=="A" and c=="B"):
            ans[0] = ans[0]+1
        if(a=="A" and c=="C"):
            ans[1] = ans[1]+1
        if(a=="B" and c=="A"):
            ans[2] = ans[2]+1
        if(a=="B" and c=="C"):
            ans[3] = ans[3]+1
        if(a=="C" and c=="A"):
            ans[4] = ans[4]+1
        if(a=="C" and c=="B"):
            ans[5] = ans[5]+1
    def Hanoi(n,a,b,c):
    	if n==0:
    	    return
    	Hanoi(n-1, a, c, b)
    	cal(a,c)
    	Hanoi(n-1, b, a, c)
    
    while True:
        try:
            n=int(input())
            ans=[0]*6 
            Hanoi(n, "A", "B", "C")
            print("A->B: ",ans[0])
            print("A->C: ",ans[1])
            print("B->A: ",ans[2])
            print("B->C: ",ans[3])
            print("C->A: ",ans[4])
            print("C->B: ",ans[5])
        except EOFError:
            break
    

    更python的写法,有可能获得超时

    ans = dict()
    def cal(a,c):
        s=a+'->'+c+':'
        ans.update({s:ans.get(s)+1})
    def Hanoi(n,a,b,c):
    	if n==0:
    	    return
    	Hanoi(n-1, a, c, b)
    	cal(a,c)
    	Hanoi(n-1, b, a, c)
    
    while True:
        try:
            n=int(input())
            ans = {'A->B:':0,'A->C:':0,'B->A:':0,'B->C:':0,'C->A:':0,'C->B:':0}
            Hanoi(n, 'A', 'B', 'C')
            for a in ans:
                print(a,ans.get(a))
        except EOFError:
            break
    

    5.6179: Alice排数字

    其实我们可以给其中的8和2拿出来看看有多少个282,排列一定是282828282····
    也就是28不断循环的,其中282的个数和2和8均有关,n个2就有n-1个282,m个8就有m个282,两者取小,当然不能是负数。
    取值是ord函数

    while True:
        try:
            s=input()
            a=[0]*10
            for c in s:
                t = ord(c)-ord('0')
                a[t] = a[t] + 1
            print(max(0,min(a[2]-1,a[8])))
            print('Happy Birthday!')
        except EOFError:
            break
    

    6.6181: Alice与闪电

    这个一个比较复杂的循环题,我们可以将其分三种输出,前m/2行,中间行,后m/2行,前m/2行前面的空格分析下,为abs(i)个,*为(m - abs(i) + 1))个,中间行是n个*,然后依次类推。
    至于中间用空行隔开,我们可以用一个旗子来表示,刚开始没有插旗子,不能输出空行,执行一次就插上了旗子,当然是否要输出空行要在插旗子之前。详见代码flag的操作。
    python直接把字符串乘起来,很方便

    flag = 0
    while True:
        try:
            n = int(input())
            if flag==1:
                print()
            flag = 1
            m = n//2
            for i in range (-m,m + 1):
                if i < 0:
                    print(' ' * abs(i) + '*' *(m - abs(i) + 1))
                elif i == 0:
                    print('*' * n)
                else:
                    print(' ' * m + '*' * (m - i + 1))
        except EOFError:
            break
    

    7.6180: Alice玩井棋

    这是一个比较有趣的游戏,但是不同的思路实现起来难度可能不同,在这里推荐了一个比较简单的实现,
    1.横或竖坐标均相同
    2.在左上到右下的对角线上
    3.在右上到左下对角线上

    while True:
        try:
            x1,y1 = map(int,input().split())
            x2,y2 = map(int,input().split())
            x3,y3 = map(int,input().split())
            if x1==x2 and x2==x3 or y1==y2 and y2==y3:
                print('Win')
            elif x1==y1 and x2==y2 and x3==y3:
                print('Win')
            elif x1+y1==4 and x2+y2==4 and x3+y3==4:
                print('Win')
            else:
                print('Continue')
        except EOFError:
            break
    

    8.6174: Alice与甜甜圈

    空圆柱体的体积,体积为底面积高,
    圆环面积为(R*R-r*r)
    PI
    可以使用math包里的PI

    import math
    while True:
        try:
            R,r,h = map(float,input().split())
            print ('%.2f' %(math.pi*h*(R*R-r*r)))
        except EOFError:
            break
    

    9.6175: Alice买口罩

    10个口罩一定会浪费掉,所以你买到y个口罩,买x个一次,次数为y/x
    python的整数除法需要"//"

    n,m=map(int,input().split())
    print (m//n)
    

    10.6176: 武汉加油!中国加油!

    简单C语言输出,可以复制粘贴,尽量减少错误

    print ("Fighting, Wuhan! Stay strong, China!")
    
  • 相关阅读:
    JQuery上传插件Uploadify使用详解
    在ASP.NET MVC中使用带后缀的URL
    设计师必备的职业素养!
    2010年最危险的IT技术是什么?
    关于百度快照的常见问题!
    设计师提高水平秘籍
    成为优秀设计师的几大条件
    2010最值得关注的10款互联网产品
    2011年网页设计趋势!!!!
    揭开网站美丽面纱!快照(百度快照,谷歌快照)。
  • 原文地址:https://www.cnblogs.com/BobHuang/p/12312134.html
Copyright © 2020-2023  润新知