题意:有一个n*m的棋盘(n,m≤80,n*m≤80)要在棋盘上放k(k≤20)个棋子,使得任意两个棋子不相邻(每个棋子最多和周围4个棋子相邻)。求合法的方案总数。

思路:对于每一行,如果把没有棋子的地方记为0,有棋子的地方记为1,那么每一行的状态都可以表示成一个2进制数,进而将其转化成10进制。

     那么这个问题的状态转移方程就变成了:

     设dp[i][j][k]表示当前到达第i行,一共使用了j个棋子,且当前行的状态在压缩之后的十进制数为k时的状态总数。那么我们也可以类似的写出状态转移方程:

   dp[i][i][k]=sum(dp[i-1][j-num(k)][w])   num(k)表示 k状态中棋子的个数,w表示前一行的状态。

最基本的做法是:首先判断k状态是否合法,也就是判断在这一行中是否有2个旗子相邻,然后枚举上一行的状态w,判断w状态是否合法,

           然后判断k状态和w状态上下之间是否有相邻的棋子。

下面是其他网上来的代码,三维状压DP

https://www.cnblogs.com/a-clown/p/6145462.html

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
using namespace std; ll dp[][][<<];///dp[i][j][x]第i行放了j个棋子当前状态为x时的方法数
ll mark[<<];///十进制标记每一行的状态
ll ans,len; ll num(ll x) ///记录状态x中1的个数
{
ll sum=;
while(x)
{
if(x&)sum++;
x=x>>;
}
return sum;
} bool judge(ll x) ///判断状态x是否有相邻的棋子放在一起
{
if(x&(x<<)) return false;
return true;
} int main()
{
//freopen("in.txt","r",stdin);
int n,m,k;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
memset(dp,,sizeof(dp));
memset(mark,,sizeof(mark));
len=,ans=;
if(m>n) swap(n,m); for(ll i=; i<(<<m); i++) ///初始化第一行的放置方法数//剔除不合法状态(所谓的预处理)
{
if(judge(i)) ///若i状态没有相邻的棋子放在一起
{
dp[][num(i)][len]=;///则第一行状态为len(i)时1的个数为num(i)时的方法数
mark[len++]=i;///标记状态
}
} for(ll i=; i<=n; i++) ///第二行到第n行
{
for(ll j=; j<=k; j++) ///对于放0***n个棋子
{
for(ll x=; x<len; x++) ///对于0***len-1个状态(第i行)//枚举
{
for(ll y=; y<len; y++)///对于0***len-1个状态(第i-1行)//枚举
{
ll tmp=num(mark[x]);///第i行状态x中1的个数
if(((mark[x]&mark[y])==) && j>=tmp) ///若上下2行没相邻的且当前的棋子数目大于此行当前状态所用的棋子
dp[i][j][x]+=dp[i-][j-tmp][y];///放法数可相加
///到当前行共用了j个棋子,当前行用了tmp个棋子,状态为x,到上一行共用了j-tmp个棋子,状态为y
}
}
}
}
for(ll i=; i<len; i++) ///枚举状态相加
ans+=dp[n][k][i];
printf("%lld\n",ans);
}
return ;
}

还有另外的代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
const int maxn=(<<)+;
const int INF=0x3f3f3f3f; ll dp[][][maxn]; ///第i行用j个棋子的k状态能否达到
int mark[maxn]; int judge(int x)
{
if(x&(x<<)) return ;
return ;
} int num(int x)
{
int sum=;
while(x)
{
if(x&) sum++;
x=(x>>);
}
return sum;
} int main()
{
//freopen("in.txt","r",stdin);
int n,m,k;
while(scanf("%d%d%d",&n,&m,&k)==)
{
memset(dp,,sizeof(dp));
memset(mark,,sizeof(mark));
int len=;
if(m>n) swap(n,m);
for(int i=; i<(<<m); i++)
{
if(judge(i))
{
dp[][num(i)][len]=;
mark[len++]=i;
}
} for(int i=; i<=n; i++)
for(int j=; j<=k; j++)
for(int x=; x<len; x++) ///当前行
for(int y=; y<len; y++) ///当前行的前一行
if(((mark[x]&mark[y])==) && j>=num(mark[x]) )
dp[i][j][x]+=dp[i-][j-num(mark[x])][y]; ll ans=;
for(int i=; i<len; i++)
ans+=dp[n][k][i];
printf("%lld\n",ans);
}
return ;
}

棋盘 || 状压DP的更多相关文章

  1. BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

    状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...

  2. [BZOJ4000][TJOI2015]棋盘(状压DP+矩阵快速幂)

    题意极其有毒,注意给的行列都是从0开始的. 状压DP,f[i][S]表示第i行状态为S的方案数,枚举上一行的状态转移.$O(n2^{2m})$ 使用矩阵加速,先构造矩阵a[S1][S2]表示上一行为S ...

  3. 【BZOJ4000】【LOJ2104】【TJOI2015】棋盘 (状压dp + 矩阵快速幂)

    Description ​ 有一个\(~n~\)行\(~m~\)列的棋盘,棋盘上可以放很多棋子,每个棋子的攻击范围有\(~3~\)行\(~p~\)列.用一个\(~3 \times p~\)的矩阵给出了 ...

  4. 暑假集训Day2 状压dp 特殊方格棋盘

    首先声明 : 这是个很easy的题 可这和我会做有什么关系 题目大意: 在n*n的方格棋盘上放置n个车,某些格子不能放,求使它们不能互相攻击的方案总数. 注意:同一行或同一列只能有一个车,否则会相互攻 ...

  5. 特殊方格棋盘【状压DP】

    特殊方格棋盘[状压DP] 讲真状压DP这个东西只不过是有那么亿丢丢考验心态罢了(确信) 先从板子题说起,另加一些基础知识 题目描述 在的方格棋盘上放置n 个车,某些格子不能放,求使它们不能互相攻击的方 ...

  6. POJ 1321 棋盘问题(DFS & 状压DP)

    用DFS写当然很简单了,8!的复杂度,16MS搞定. 在Discuss里看到有同学用状态压缩DP来写,就学习了一下,果然很精妙呀. 状态转移分两种,当前行不加棋子,和加棋子.dp[i][j]中,i代表 ...

  7. poj 3254 Corn Fields (状压dp)(棋盘dp)

    状压dp入门题 因为当前行的状态只和上一行有关 所以可以一行一行来做 因为m <= 12所以可以用二进制来表示放了或者没有放 0表示没放,1表示放 f[i][state]表示第i行状态为stat ...

  8. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  9. 【BZOJ1087】 [SCOI2005]互不侵犯King 状压DP

    经典状压DP. f[i][j][k]=sum(f[i-1][j-cnt[k]][k]); cnt[i]放置情况为i时的国王数量 前I行放置情况为k时国王数量为J #include <iostre ...

随机推荐

  1. mysql免安装版配置启动时出错

    今天安装了MySQL5.7的免安装版本,启动时报了服务无法启动的错误,在网上找了好久终于找到了解决方法 我找到解决方法的博客地址是:http://blog.csdn.net/qq_27093465/a ...

  2. Top 9 colleges in the world from 2010 to 2020, AI and interdisciplinary areas.

    http://csrankings.org/

  3. 【兆易创新RISC-V开发板评测】01.干货分享

    背景介绍:2019年12月19日在面板包偶然发可以免费申请测评GD32VF103开发板,欣喜万分:在这之前各大技术论坛说是已经有国产兆易创新的RISCV指令集的MCU发布的事情,一时间摩拳擦掌想购入一 ...

  4. kubernetes的Ingress资源介绍

    Ingress 的资源帮助信息介绍 [root@master ~]# kubectl explain ingress KIND: Ingress VERSION: extensions/v1beta1 ...

  5. h5页面判断移动端系统为Android或IOS

    最近遇到了一个需求,即所谓的 app+web 混合开发,需要将 h5 内嵌到 APP 中,这个时候因为要对 Android 和 IOS 有不同的处理逻辑,所以我们就需要判断一下,移动端的系统到时是哪一 ...

  6. 解决mysql和navicat乱码问题

    1,首先进入mysql的my.ini文件,进行编码修改,全部改成utf8编码(这里就不赘述了,网上一搜一堆) 2,最重要的一点,把原先navicat创建的连接断开,重新创建新连接,在该新连接下创建库, ...

  7. 【转载】Linux截图工具

    如果linux安装了gnome,那么系统自带了一款截屏软件 gnome-screenshot,使用起来很方便,功能齐备,支持命令行.简单介绍如下. 功能 对屏幕,窗口,或自定义的区域进行截图. 选项 ...

  8. query_phase_execution_exception

    ES报错信息: { "error": { "root_cause": [ { "type": "query_phase_execu ...

  9. inline-block,真的懂吗

    曾几何时,display:inline-block 已经深入「大街小巷」,随处可见 「display:inline-block; *display:inline; *zoom:1; 」这样的代码.如今 ...

  10. Java面向对象编程 -3.3

    综合实战 简单Java类 在以后进行项目开发与设计的过程之中,简单Java类都将作为一个重要的组成部分存在,慢慢接触到正规的项目设计后, 简单Java类无处不再,并且有可能产生一系列的变化. 所谓的简 ...