蓝桥杯 ALGO-1005 数字游戏 python

蓝桥杯 ALGO-1005 数字游戏 python

试题 算法训练 数字游戏

资源限制

时间限制:1.0s 内存限制:256.0MB

问题描述

给定一个1~N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列都比上一次的序列长度少1,最终只剩一个数字。
  例如:
  3 1 2 4
  4 3 6
  7 9
  16
  现在如果知道N和最后得到的数字sum,请求出最初序列a[i],为1~N的一个排列。若有多种答案,则输出字典序最小的那一个。数据保证有解。

输入格式

第1行为两个正整数n,sum

输出格式

一个1~N的一个排列

样例输入

4 16

样例输出

3 1 2 4

数据规模和约定

0<n<=10

解题思路

其实这道题,我真的是跌宕起伏,如果是C++我可能早就写出来了吧,但是由于是python,很多解就不能暴力搜索了,要不然1-10的暴力搜索也不是不可以,孩子快哭了,不过无所谓,就当锻炼算法吧

首先给出两个70分的代码,在这两个code之中,都有一些比较好的思想,第一个就是可以直接利用我们内置库函数,对我们给出的数组进行一个全排列,然后我们直接累加迭代发现sum一样不就可以了么,这多么简单啊,还要搞什么呀哈哈哈,结果70分,有些案例就是过不了,时间直接TLE,让人绝望啊,先给出代码,代码思想很简单,就是得到全排列然后累加求和

内置库运用70分

import itertools
a = list(range(1,n+1))
n,sum = map(int,input().split())
for l in itertools.permutations(a,n):
     l = list(l)
     # print(l)
     l2 = l[:]
     for i in range(n-1):
         for j in range(n-1-i):
             l[j] += l[j+1]
             
     if l[0] == sum:
         for i in l2:
             print(i,end=' ')
         break

结果只有70分

然后行吧,用点算法吧,用搜索咯,那肯定是比较常见又简单的DFS咯,很简单的想法,我们可以在本身的数组上进行一个累加,这样最后得到的结果元素1也就是我们的s[0] 如果是sum的时候,我们就可以直接打印出结果了。

然后后面一段就是用dfs思想了,如果visit过了就换一个的,不断的迭代,直到有n个数据,我们才进行判断

DFS 70分

s = [0]*n
d = [0]*n
vis = [0]*n
n,sum = map(int,input().split())
def dfs(step):
    if step == n:
        s = d[:]
        for i in range(n-1):
            for j in range(n-1-i):
                s[j] += s[j+1]
        if s[0] == sum:
            print(' '.join(str(i) for i in d))
            return True
        else:
            return False

    for i in range(0,n):
        if vis[i] == 1:
            continue
        vis[i] = 1
        d[step] = i + 1
        if dfs(step+1):
            return True
        vis[i] = 0
    return False

dfs(0)

但是结果还是差强人意,虽然会比上面的时间复杂度低一点,但是还是70分啊,还有样例还是过不了,我差点绝望了,我就看啊看,到底有什么算法可以解决。其实对于我们的程序来说,最耗时间的一部分第一个是我们的赋值,我们的d赋值可以利用append,pop这些时间比较少的,其次就是我们求和那一部分是一个二重循环,时间复杂度比较高。

然后我就思前想去,突然,我在想,每一行中的数据求和与我们最后得到的和有什么关系么,后面,我终于悟到了,杨辉三角!!!

这不就是一个典型的杨辉三角么,按样例来看,杨辉三角的底层是1 3 3 1,求和就是3x1 + 1x3+ 2x3 + 4x1 = 16,哇,这么说的话,其实我并不用算太多,我可以直接进行一个计算杨辉三角的底层,只有一个循环,这就简单了

在这里插入图片描述

所以首先小小改进了一下

改进的90分代码

# return 杨辉三角的最后一行
def yh(num):
    if num == 1:
        res = [1]
    else:
        res = [[0]*num for i in range(num)]
        for i in range(num):
            for j in range(num):
                res[i][0] = 1
                if i == j:
                    res[i][j] = 1
        for i in range(2,num):
            for j in range(1,i):
                res[i][j] = res[i-1][j-1] + res[i-1][j]
    return res[num-1]

n,sum = map(int,input().split())
yh = yh(n)

d = [0]*n
vis = [0]*n

def dfs(step):
    if step == n:
        s = 0
        for i in range(n):
            s += d[i]*yh[i]        
        if s == sum:
            print(' '.join(str(i) for i in d))
            return True
        else:
            return False

    for i in range(0,n):
        if vis[i] == 1:
            continue
        vis[i] = 1
        d[step] = i + 1
        if dfs(step+1):
            return True
        vis[i] = 0
    return False
if n == 1:
    print(sum)
else:
	dfs(0)

结果还是大意了,只有80,所以其实在我们的DFS中,我们还需要一些剪枝之类的操作才可以得到比较好的结果,所以用同样的想法进行一个改进,最后终于圆满了,我们可以在本身要计算的时候,传入的就是求和的结果,如果大于我们需要的sum就直接break,也就是剪枝了,这样可能就比较好,减少了循环的计算。

完美的100分代码

# return 杨辉三角的最后一行
def yh(num):
    if num == 1:
        res = [1]
    else:
        res = [[0]*num for i in range(num)]
        for i in range(num):
            for j in range(num):
                res[i][0] = 1
                if i == j:
                    res[i][j] = 1
        for i in range(2,num):
            for j in range(1,i):
                res[i][j] = res[i-1][j-1] + res[i-1][j]
    return res[num-1]

n,sum = map(int,input().split())
yh = yh(n)

d = []
vis = [0]*(n+1)

def dfs(step,s):
    if s > sum:
        return False
    if step == n:
        if s == sum:
            print(' '.join(str(i) for i in d))
            return True
        else:
            return False

    for i in range(1,n + 1 ):
        if vis[i] == 0:
            vis[i] = 1
            d.append(i)
            if dfs(step+1,s+yh[step]*i):
                return True
            vis[i] = 0
            d.pop()
    return False
if n == 1:
    print(sum)
else:
    dfs(0,0)

所以最后终于AC了,结束了,good,还好成功了,没有放弃

每日一句

What doesn’t kill you makes you stronger.

没能摧毁你的,必使你强大。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>