[编程题]创造新世界/牛客网/Python/解题报告+源代码

题目:https://www.nowcoder.com/questionTerminal/b8bc8459f0d34aaa8c1af1328cab2432


算是0-1背包问题的升级版本,用动态规划算法来解决。


方法一:




val[k][i][j]代表对前k个item来说(共x个),当0和1的最大数量分别为i和j时,最多能创造的01串的种类。

状态转移方程:val[k][i][j] = max(val[k-1][i][j], 1 + val[k-1][i-w0][j-w1])



 def creatNewWorld():
    firstline = input()
    # nums = [int(n) for n in firstline.split()]
    # x, n, m = nums[0], nums[1], nums[2]
    x, n, m = [int(n) for n in firstline.split()]
    items = []
    for i in range(x):
        item = str(input())
        items.append(item)
    #print (x,n,m,items)

    val = [[[None for i in range(m+1)] for j in range(n+1)] for k in range(x+1)]

    #print(val[0][0][0]+1)
    for i in range(n + 1):
        for j in range(m + 1):
            val[0][i][j] = 0


    for k in range(1,x+1):
        w0, w1 = count0and1(items[k-1])
        for i in range(n+1):
            for j in range(m+1):
                if w0 > i or w1 > j:
                    val[k][i][j] = val[k-1][i][j]
                else:
                    val[k][i][j] = max(val[k-1][i][j], 1 + val[k-1][i-w0][j-w1])

    print(val[x][n][m])


def count0and1(item):
    c1 = 0
    for n in item:
        if int(n) == 1:
            c1 += 1
    return len(item) - c1, c1

creatNewWorld()

结果:空间超了。


改进的方法二:



三维数组太耗时间。由状态转移方程:val[k][i][j] = max(val[k-1][i][j], 1 + val[k-1][i-w0][j-w1])可以看到,val[k][i][j] 只和val[k-1][...][...]有关,所以可以压缩成二维数组来存状态。
注意:这里在循环的时候,i和j要逆序地循环,这是因为val[i][j] = max(val[i][j], 1 + val[ i-zeros[k-1] ][ j-ones[k-1] ]),i和j较大的val的计算基于i和j较小的val的值,如果i和j从小到大循环,就重复计数了。

def creatNewWorld():
    firstline = input()
    x, n, m = [int(n) for n in firstline.split()]
    zeros = [ 0 for i in range(x)]
    ones = [ 0 for i in range(x)]
    for i in range(x):
        item = str(input())
        zeros[i], ones[i] = count0and1(item)


    val = [[0 for i in range(m + 1)] for j in range(n + 1)]
    for k in range(1,x+1):
        for i in range(n, zeros[k-1] - 1, -1):
            for j in range(m, ones[k-1] - 1, -1):
                    val[i][j] = max(val[i][j], 1 + val[ i-zeros[k-1] ][ j-ones[k-1] ])

    print(val[n][m])

def count0and1(item):
    c1 = 0
    for n in item:
        if int(n) == 1:
            c1 += 1
    return len(item) - c1, c1

creatNewWorld()


但是依然超时,70%case能成功。进过慎重地排除,我觉得是牛客网的oj系统造成的,本身代码没问题。确切地说也不是牛客网的问题,牛客网无论什么题目什么语言就限时1s,同样地算法用java写一遍可以通过,改成python就超时了,毕竟python效率不够高。我在评论区也找到一个用python的也是这种情况,总是到70%case就超时。代码我自己用pycharm测试了好多次,是没问题的。


扩展问题:
这个题目让求的是【最多能创造几种01串】,不过在一开始很容易让人看错成【最多能创造几个01串】。所以思考一下扩展问题【最多能创造几个01串】呢?
原问题相当于一种01串只能创造一次,拓展问题相当于一种01串可以创造多次。
只要改一个地方就可以了——那就是方法二中强调了i和j要逆序循环,在这个问题中,改成正序循环就可以了。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值