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\) 相邻
则可以构造出形如:\(x\underline{ }x\underline{}x\underline{}x\underline{}...\) 的旗帜,下换线所指任意空缺位置可以是 \(y\) 或 \(z\) 的其中一种。因此旗帜个数是关于2的指数级别,可以保证在这种情况下 \(k\) 足够小以致根本不用担心时间效率问题。
另一方面,不是这种情况的颜色搭配意味着任意一种颜色只能与唯一一种颜色相邻或者不能与任何颜色相邻。
令 \(valid\) 表示可以与唯一一种颜色相邻的颜色个数,\(m\) 表示颜色总数,\(striple\) 表示使得旗帜个数大于等于 \(numFlags\) 的最小条纹数,则:
\(striple=ceil(\frac{numFlags+valid-m}{valid})\)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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)
PS:当时SB的用了一个二分搜索+数列递推矩阵的算法来作,写了整整一个通宵才搞定......