• SRM147 DIV1 1000


    动态规划的题,令 (dp[k][i]) 表示最后一个条纹的颜色为 (i) 且条纹数小于等于 (k) 时的旗帜个数,则有:

    (dp[k][i] = 1+sum^{颜色(j,i)可以相邻}dp[k-1][j])

    初始状态:(dp[1][i]=1)

    计算最小的 (k) 使得 (sum_i dp[k][i] geq numFlags)

    (k) 可能取得很大,时间上可能不允许做这么多次操作,注意到下面这种情况:

    存在任意一种颜色 (x) 可以与至少两种颜色 (yz) 相邻

    则可以构造出形如:(xunderline{ }xunderline{}xunderline{}xunderline{}...) 的旗帜,下换线所指任意空缺位置可以是 (y) 或 (z) 的其中一种。因此旗帜个数是关于2的指数级别,可以保证在这种情况下 (k) 足够小以致根本不用担心时间效率问题。

    另一方面,不是这种情况的颜色搭配意味着任意一种颜色只能与唯一一种颜色相邻或者不能与任何颜色相邻。

    令 (valid) 表示可以与唯一一种颜色相邻的颜色个数,(m) 表示颜色总数,(striple) 表示使得旗帜个数大于等于 (numFlags) 的最小条纹数,则:

    (striple=ceil(frac{numFlags+valid-m}{valid}))

     1 import math
     2 
     3 class Flags:
     4     def numStripes(self, numFlags, forbidden):
     5         numFlags = int(numFlags)
     6         m = len(forbidden)
     7         marks = [[True for j in range(m)] for i in range(m)]
     8         for i in range(m):
     9             s = forbidden[i].split(' ')
    10             for ch in s:
    11                 j = int(ch)
    12                 marks[i][j] = False
    13 
    14         flag = True
    15         valid = 0
    16         for i in range(m):
    17             cnt = marks[i].count(False)
    18             if cnt < m:
    19                 valid += 1
    20             if cnt < m - 1:
    21                 flag = False
    22 
    23         if flag:
    24             return math.ceil((numFlags + valid - m) / valid)
    25 
    26 
    27         dp = [1] * m
    28         k = 1
    29         while True:
    30             if sum(dp) >= numFlags:
    31                 return k
    32             dp2 = [1] * m
    33             for i in range(m):
    34                 for j in range(m):
    35                     if marks[j][i]:
    36                         dp2[i] += dp[j]
    37             k += 1
    38             dp = dp2
    39 
    40 
    41 # test
    42 o = Flags()
    43 
    44 # test else
    45 assert(o.numStripes("10", ("0 2 3", "1 2 3", "0 1 2 3", "0 1 2 3")) == 4)
    46 
    47 # test case
    48 assert(o.numStripes("10", ("0","1 2","1 2")) == 3)
    49 assert(o.numStripes("100", ("0","1","2")) == 6)
    50 assert(o.numStripes("100000000000000000", ("0","1")) == 50000000000000000)
    51 assert(o.numStripes("10000000000000000", ("0 1", "0 1", "2 3 4", "2 3 4", "2 3 4")) == 40)
    52 assert(o.numStripes("10000000000000000", ("0 1 2 3 4 5 6 7 8 9", "0 1 3 4 5 6 7 8 9", "0 2 3 4 5 6 7 8 9", "0 1 2 3 4 5 6 7 8 9", 
    53 "0 1 2 3 4 5 6 7 8 9", "0 1 2 3 4 5 6 7 8 9", "0 1 2 3 4 5 6 7 8 9", 
    54 "0 1 2 3 4 5 6 7 8 9", "0 1 2 3 4 5 6 7 8 9", "0 1 2 3 4 5 6 7 8 9")) == 4999999999999996)
    55 assert(o.numStripes("5", ("0","1","2","3","4","5")) == 1)
    View Code

    PS:当时SB的用了一个二分搜索+数列递推矩阵的算法来作,写了整整一个通宵才搞定......

  • 相关阅读:
    docker-compose 使用
    mysql UNIX时间戳与日期的相互转换 查询表信息
    mysql查看表结构命令
    PostgreSQL新手入门
    ibdata1是?
    ubuntu 12.04 安装 nginx+php+mysql web服务器
    读懂IL代码就这么简单(二)
    读懂IL代码就这么简单(一)
    在Ubuntu Linux下怎样安装QQ
    jQuery 选择器
  • 原文地址:https://www.cnblogs.com/valaxy/p/3444798.html
Copyright © 2020-2023  润新知