【算法训练营】刷油漆,n皇后(python实现)

文章讨论了如何使用动态规划策略解决两种问题:一是给定车辆和油漆颜色限制,计算满足相邻车辆颜色不同的涂漆方案数量;二是n皇后问题中计算放置皇后以避免冲突的方案数。通过状态转移和剪枝优化算法来求解。
摘要由CSDN通过智能技术生成

刷油漆


描述

有n辆车排成一排,还有m种不同颜色的油漆,其中第i种油漆够涂ai辆车,同时所有油漆恰好能涂完n辆车。若任意两辆相邻的车颜色不能相同,有多少种涂油漆的方案?

输入

第一行包含一个正整数m。

接下来一行包含m个正整数,第i个正整数表示ai。

输出

输出一个整数,表示答案除以23333的余数。

样例1输入

3
2 1 3

样例1输出

10

样例1解释

10个方案分别是:

1 3 1 3 2 3
1 3 2 3 1 3
2 3 1 3 1 3
3 1 2 3 1 3
3 1 3 1 2 3
3 1 3 1 3 2
3 1 3 2 1 3
3 1 3 2 3 1
3 2 1 3 1 3
3 2 3 1 3 1

样例2

请查看下发文件内的sample2_input.txt和sample2_output.txt。

限制

n为ai之和。

对于50%的数据,n ≤ 10;

对于100%的数据,m ≤ 20,ai ≤ 5。

时间:10 sec

空间:512 MB

提示

[注意到ai≤5,所以我们可以将“还能涂1辆车的油漆种类数”、“还能涂2辆车的油漆种类数”、...、“还能涂5辆车的油漆种类数”设计成状态,思考一下便能得到转移。]

代码实现 

N = 21
mo = 23333

# f: records previously calculated answers to reduce redundant calculations
f = [[[[[[-1 for _ in range(6)] for _ in range(N)] for _ in range(N)] for _ in range(N)] for _ in range(N)] for _ in
     range(N)]


# Dynamic programming (memoization strategy search) to find the number of painting schemes
def dp(a, b, c, d, e, last):
    if (a | b | c | d | e) == 0:
        return 1

    if f[a][b][c][d][e][last] != -1:
        return f[a][b][c][d][e][last]

    ret = 0

    if a:
        ret += dp(a - 1, b, c, d, e, 1) * (a - (last == 2))
    if b:
        ret += dp(a + 1, b - 1, c, d, e, 2) * (b - (last == 3))
    if c:
        ret += dp(a, b + 1, c - 1, d, e, 3) * (c - (last == 4))
    if d:
        ret += dp(a, b, c + 1, d - 1, e, 4) * (d - (last == 5))
    if e:
        ret += dp(a, b, c, d + 1, e - 1, 5) * e

    f[a][b][c][d][e][last] = ret % mo
    return f[a][b][c][d][e][last]


# b: b[i] represents how many paint types are enough for i cars
b = [0, 0, 0, 0, 0, 0]


# n cars, m paint types, the ith paint type is enough for ai cars, and all paint types can exactly paint n cars.
# If any two adjacent cars cannot have the same color, how many painting schemes are there?
def getAnswer(m, a):
    global f, b
    f = [[[[[[-1 for _ in range(6)] for _ in range(N)] for _ in range(N)] for _ in range(N)] for _ in range(N)] for _ in
         range(N)]

    for i in range(m):
        b[a[i]] += 1

    return dp(b[1], b[2], b[3], b[4], b[5], 0)


if __name__ == "__main__":
    m = int(input())
    a = list(map(int, input().split()))
    print(getAnswer(m, a))

n皇后


描述

n皇后问题:一个n×n的棋盘,在棋盘上摆n个皇后,满足任意两个皇后不能在同一行、同一列或同一斜线上的方案有多少种?

输入

第一行包含一个整数n。

输出

输出一个整数,表示方案数。

样例1输入

4

样例1输出

2

样例2

请查看下发文件内的sample2_input.txt和sample2_output.txt。

限制

一共10个测试点, 第i个测试点的n=i+4。

时间:2 sec

空间:512 MB

提示

python同学注意,标程后两个测试点10s都过不去,故自行打表。

[考察剪枝水平,剪枝剪得好(二进制剪枝)的才能过第10个测试点。]

代码实现 

def test(row, ld, rd, ans, all_one):
    if row != all_one:
        pos = all_one & ~(row | ld | rd)
        while pos:
            p = pos & -pos
            pos -= p
            test(row | p, (ld | p) << 1, (rd | p) >> 1, ans, all_one)
    else:
        ans[0] += 1

def get_answer(n):
    ans = [0]
    all_one = (1 << n) - 1
    test(0, 0, 0, ans, all_one)
    return ans[0]

if __name__ == "__main__":
    n = int(input())
    print(get_answer(n))

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X.AI666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值