09267: 核电站
dfs, dp, http://cs101.openjudge.cn/practice/09267/
一个核电站有 N 个放核物质的坑,坑排列在一条直线上。如果连续 M 个坑中放入核物质,则会发生爆炸,于是,在某些坑中可能不放核物质。
任务:对于给定的 N 和 M ,求不发生爆炸的放置核物质的方案总数。
输入
只有一行,两个正整数 N,M (1 < N < 50, 2 <= M <= 5)。
输出
一个正整数 S,表示方案总数。
样例输入
4 3样例输出
13参考:https://blog.csdn.net/weixin_50624971/article/details/117337552
这题和放苹果挺类似的,都是要分情况讨论i和m的大小关系 case1:如果i<m 这说明在这段区间里怎么放都不会炸,那么状态转移方程就是:a[i]=2*a[i-1].(乘2是因为每个坑有放和不放两种情况) case2:如果i==m 情况同case1,只是要减去区间全放(会炸)的情况,那么状态转移方程就是:a[i]=2*a[i-1]-1. case3:如果i>m 这是就要考虑会炸的情况了。我们采用减法的方式——即从总情况里减去会炸的情况。 如果第i位是不能放的,那么说明i-m这段区间肯定全放了,而且i-m-1这一位一定是0,因为如果该位是1的话就会在之前被处理掉,所以如果i为不能放,那么i-m-1这段区间的所有可能都需要从答案里减掉。那么状态转移方程就是:a[i]=2*a[i-1]-a[i-1-m]
python
# 23n1900014516
n, m = map(int, input().split())
DP = [0] * 60
DP[0] = 1 #DP[i]是第i个位置的方案数。
for i in range(1, n + 1):
if i < m: #达不到连续放置m个的情况
DP[i] = DP[i - 1] * 2 # 从第1个到第m-1个,方案都可以选择放/不放
elif i == m: #第m个要小心了
DP[i] = DP[i - 1] * 2 - 1
else:#i>m
DP[i] = DP[i - 1] * 2 - DP[i - m - 1]
print(DP[n])python
from functools import lru_cache
@lru_cache(maxsize=None)
def dfs(i, j, n, m):
if j == m:
return 0 # 如果有连续的m个坑都有物质,此方案不可行
if i == n:
return 1 # 如果能到n,说明之前没有连续的m个坑都有物质,此方案可行
# 不在第i个坑放置物质
no_place = dfs(i + 1, 0, n, m)
# 在第i个坑放置物质
place = dfs(i + 1, j + 1, n, m)
# 计算总数
return no_place + place
if __name__ == "__main__":
n, m = map(int, input().split())
result = dfs(0, 0, n, m)
print(result)python
n = 0
m = 0
ans = 0
memo = {}
def dfs(i, j):
if j == m:
return 0 # 如果有连续的m个坑都有物质,此方案不可行
if i == n:
return 1 # 如果能到n,说明之前没有连续的m个坑都有物质,此方案可行
if (i, j) in memo:
return memo[(i, j)]
ans = dfs(i+1, 0) # 第i个坑里没有物质,之后的坑里是否放物质与前面没有联系了
ans += dfs(i+1, j+1) # 前i个坑中最后连续j个坑里都有物质
memo[(i, j)] = ans
return ans
if __name__ == "__main__":
res = 0
n, m = map(int, input().split())
res = dfs(0, 0) # 从第0个坑里开始放
print(res)