洛谷P1896_状压dp

本弱第一篇状压dp(在看了题解的前提下做的)


在n*n个格子内放m个国王,要求国王的四周即周围8个格子不能再有国王,求不同的放置方案数
将任意一行的一个状态看作是n位的二进制数,1表示放了国王,0表示没有放
dp[i][j][k] 表示前i行第j个状态,已经放置了k个国王的方案数;
can[i]第i个状态的数字,num[i]第i个状态的1的个数;

#include <cstdio>
#include <cstring>

using namespace std;

typedef long long LL;

int n, m;//n*n的格子放m个
LL dp[11][1111][111];//前i行,第j个状态,共有k个国王的方案数

int can[1111], num[1111];//满足条件的数,以及它的含1的个数
int tot;

int getnum(int x)
{
    int ret = 0;
    while(x) ret += (x&1), x>>=1;
    return num[tot] = ret;
}

int main()
{
    int i, j, k, l, x, y;
    scanf("%d %d", &n, &m);
    memset(dp, 0, sizeof(dp));
    int maxn = (1<<n)-1;
    tot = 0;
    for(i = 0; i <= maxn; ++i)
        if(!(i&(i<<1)))//若二进制没有连续的1
            can[++tot] = i, dp[1][tot][getnum(i)] = 1;
    for(i = 2; i <= n; ++i)//枚举行号
        for(j = 1; j <= tot; ++j)//枚举第i行的状态
    {
        x = can[j];
        for(k = 1; k <= tot; ++k)//枚举第i-1行的状态
        {
            y = can[k];
            if((x&y) || (x&(y<<1)) || (x&(y>>1))) continue;
            for(l = 0; l <= m; ++l) dp[i][j][num[j]+l]+=dp[i-1][k][l];//更新状态
        }
    }
    LL ans = 0;
    for(i = 1; i <= tot; ++i) ans += dp[n][i][m];
    printf("%lld\n", ans);
    return 0;
}
### 关于缩动态规划(DP)的相关题目与教程 #### 平台上的资源推荐 作为一个优质的在线编程练习网站,提供了大量有关缩动态规划的学习资料和实战题目。对于想要深入理解并掌握这一复杂算法的人来说,这些资源非常有价值。 #### 推荐的经典入门题库 - **P1433 吃奶酪**:这道题不仅涉及到了深度优先搜索加缩的思想,还融合了动态规划的概念,在解决过程中能够很好地锻炼选手对多种算法组合运用的能力[^2]。 - **PRZ - POI2004**:此问题同样是一道典型的缩动态规划应用实例,通过该题目的训练可以帮助加深对这类问题处理方法的理解[^3]。 #### 学习路径建议 为了更好地理解和实践缩动态规划,建议按照如下顺序逐步推进: - 熟悉二进制位运算操作的基础知识,这是实现高效编码的关键技能之一; - 复习基本的动态规划理论及其常见应用场景; - 结合具体案例研究如何定义合适的态表示形式以及设计有效的态转移方程; ```python def dp_solution(): """ 这里提供了一个简化版的缩动态规划框架, 实际编写时需根据具体问题调整参数设置及逻辑流程。 """ n = ... # 输入规模大小 state_size = 1 << n # 总共可能存在的不同态数 # 初始化记忆化数组,默认值设为无穷大或其他不可能取到的最大/最小边界条件 memo = [-1] * state_size def dfs(current_state, current_index): nonlocal memo if all_bits_set(current_state): return cost_to_end[current_index] if memo[current_state] != -1: return memo[current_state] min_cost = float('inf') for next_index in range(n): new_state = update_state_with_next_move(current_state, next_index) transition_cost = calculate_transition_expense(current_index, next_index) total_cost = transition_cost + dfs(new_state, next_index) min_cost = min(min_cost, total_cost) memo[current_state] = min_cost return min_cost result = dfs(initial_state(), start_position()) return result ``` 上述代码片段展示了利用函数`dfs()`来进行带备忘录的记忆化搜索过程,其中包含了几个重要的组成部分如初始化全局变量、判断终止条件、剪枝优化等技巧来提高求解效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值