栅栏染色

题目描述:我们有一个栅栏,它有n个柱子,现在要给柱子染色,有k种颜色可以染。必须保证最多只有两个相邻的柱子颜色相同,求有多少种染色方案。

样例:n = 3, k = 2, return 6

        post 1,   post 2, post 3

way1     0         0        1 

way2     0         1        0

way3     0         1        1

way4     1         0        0

way5     1         0        1

way6     1         1        0


我把题目稍微改了一下,这才是这道题要表达的意思,lintcode网站上题目的描述是错误的。

想一想,最多只能有两个相邻的柱子颜色相同,那也就是说,任何一个柱子的颜色,都是与他上一个柱子以及上上个柱子的颜色是有关系的。如果他和上一个柱子颜色相同,那么就必须和上上个柱子颜色不同,如果和上一个柱子颜色不同,那么当前柱子的颜色与上上个柱子就没什么关系了。

以上是基本逻辑,既然与之前的结论有关,那么可以考虑用动态规划。先看状态转移方程:

我们用一个表格record记录染色到第i个柱子时,所有染色的方案种数,显然,record[0]表示对第一个柱子的染色方案,一共有k种;record[1]表示对前2个柱子的染色方案,record[1] = k * k,因为可以有两个相邻柱子颜色相同嘛。染色到第3个柱子时,情况就有点意思了:

1. 如果第3个柱子的颜色跟第2个一样,那么他必须跟第一个柱子不一样,所以,前3个柱子的染色方案有k * (k - 1)种

2. 如果第3个柱子的颜色跟第2个不一样,那么他跟第一个柱子没关系了,所以,前3个柱子的染色方案有k * k * (k - 1)种

写出状态转移方程:record[i] = record[i - 2] * (k - 1) + record[i -1] * (k - 1)

再看初始值,就是我们刚才分析的record[0] = k; record[1] = k * k

给出代码:

class Solution:
    # @param {int} n non-negative integer, n posts
    # @param {int} k non-negative integer, k colors
    # @return {int} an integer, the total number of ways
    def numWays(self, n, k):
        if n == 0 or k == 0:
            return 0
        record = [k, k * k]
        index = 2
        while index < n:
            record.append(record[-1] * (k - 1) + record[-2] * (k - 1))
            index += 1
        return record[n - 1]
        # Write your code here


可以再把上面的代码的空间效率优化一下,用只有两个元素的数组循环:

class Solution:
    # @param {int} n non-negative integer, n posts
    # @param {int} k non-negative integer, k colors
    # @return {int} an integer, the total number of ways
    def numWays(self, n, k):
        if n == 0 or k == 0:
            return 0
        record = [k, k * k]
        if n == 1:
            return record[0]
        else:
            index = 2
            while index < n:
                temp = record[-1] * (k - 1) + record[-2] * (k - 1)
                record[0] = record[1]
                record[1] = temp 
                index += 1
        return record[1]
        # Write your code here




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值