状压DP学习笔记(持续更新ing)

前言:

最近学了这个神奇的东东,真的好难啊[仙女叹气]~

感觉自己没大理解,就写笔记强迫自己学会吧QAQ


定义:

状态压缩动态规划,就是我们俗称的状压 D P DP DP,是利用计算机二进制的性质来描述状态的一种 D P DP DP方式。

自己的小理解:其实就是将状态压缩成二进制下的数( 1 / 0 1/0 1/0)来表示不同情况,进行 D P DP DP……


前置知识:
  • 二进制位运算
  • D P DP DP
  • 以及一个聪明的小脑袋瓜;

位运算介绍:

一个神奇的东西……

推荐博客

状压 D P DP DP里主要用到的几个技巧见下图:

状压DP常用的二进制技巧


引入:

题目 :互不侵犯

题意简述

N × N N×N N×N的棋盘里面放 K K K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到他周围的8个格子。

题目分析

d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示第 i i i行状态为 j j j,一共放了 k k k个国王时的方案数。

当前方案数仅与上一行有关 ( ( 每一行只需要判断与上一行是否攻击 ) )

状态转移方程:

d p [ i ] [ j ] [ k ] + = d p [ i − 1 ] [ s ] [ k − c n t ( s ) ] dp[i][j][k] += dp[i - 1][s][k - cnt(s)] dp[i][j][k]+=dp[i1][s][kcnt(s)]

s s s为上一行满足条件的状态, c n t cnt cnt是上一行摆放的国王数量。

最终答案:

再次枚举每一个状态:

a n s + = d p [ n − 1 ] [ s ] [ k ] ans += dp[n - 1][s][k] ans+=dp[n1][s][k];

完整代码

#include <cstdio>
#include <cmath>
#include <algorithm>
#define ll long long//不开long long见祖宗 
using namespace std;
int n,k,cnt[1 << 15];
ll ans,dp[15][1 << 15][100];//状态:1表示该位置放了国王,0没有放 
bool flag[1 << 15];
int Count(int x) {
   
	int res = 0;
	while(x) {
   
		res += x & 1;
		x >>= 1;
	}
	return res;
}
bool check1(int x) {
   
	for(int i = 0; i + 1 < n; i ++) {
   
		if((x & (1 << i)) && (x & (1 << (i + 1))))
			return 0;//如果有相邻的国王,不符条件 
	} 
	return 1;
}
bool check2(int x,int y) {
   
	for(int i = 0; i < n; i ++) {
   
		if(x & (1 << i)) {
    
			if(y & (1 << i)) return 0;//上为1 
			if(i + 1 < n && (y & (1 << (i + 1)))) return 0;//左上为1 
			if(i - 1 < n && (y & (1 << (i - 1)))) return 0;//右上为1 
		}
	}
	return 1;
}
signed main() {
   
	scanf("%d %d",&n,&k);
	int m = 1 << n;
	for(int i = 0; i < m; i ++) {
   
		flag[i] = 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值