棋盘 || 状压DP
题意:有一个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的更多相关文章
- BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )
状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) ------------------------------------------------------- ...
- [BZOJ4000][TJOI2015]棋盘(状压DP+矩阵快速幂)
题意极其有毒,注意给的行列都是从0开始的. 状压DP,f[i][S]表示第i行状态为S的方案数,枚举上一行的状态转移.$O(n2^{2m})$ 使用矩阵加速,先构造矩阵a[S1][S2]表示上一行为S ...
- 【BZOJ4000】【LOJ2104】【TJOI2015】棋盘 (状压dp + 矩阵快速幂)
Description 有一个\(~n~\)行\(~m~\)列的棋盘,棋盘上可以放很多棋子,每个棋子的攻击范围有\(~3~\)行\(~p~\)列.用一个\(~3 \times p~\)的矩阵给出了 ...
- 暑假集训Day2 状压dp 特殊方格棋盘
首先声明 : 这是个很easy的题 可这和我会做有什么关系 题目大意: 在n*n的方格棋盘上放置n个车,某些格子不能放,求使它们不能互相攻击的方案总数. 注意:同一行或同一列只能有一个车,否则会相互攻 ...
- 特殊方格棋盘【状压DP】
特殊方格棋盘[状压DP] 讲真状压DP这个东西只不过是有那么亿丢丢考验心态罢了(确信) 先从板子题说起,另加一些基础知识 题目描述 在的方格棋盘上放置n 个车,某些格子不能放,求使它们不能互相攻击的方 ...
- POJ 1321 棋盘问题(DFS & 状压DP)
用DFS写当然很简单了,8!的复杂度,16MS搞定. 在Discuss里看到有同学用状态压缩DP来写,就学习了一下,果然很精妙呀. 状态转移分两种,当前行不加棋子,和加棋子.dp[i][j]中,i代表 ...
- poj 3254 Corn Fields (状压dp)(棋盘dp)
状压dp入门题 因为当前行的状态只和上一行有关 所以可以一行一行来做 因为m <= 12所以可以用二进制来表示放了或者没有放 0表示没放,1表示放 f[i][state]表示第i行状态为stat ...
- BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3336 Solved: 1936[Submit][ ...
- 【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 ...
随机推荐
- emoji web端处理
1.发送给服务器端的信息,因为图片是选择的在web端只提供了50个表情选择,所以将 #哈哈# ,凡是# #包裹的内容转化成对应的unicode编码, 比如U+1F603.每一个对应起来,这一点比较麻 ...
- JIT对锁的优化- 锁消除和锁粗化案例分析
锁消除和锁粗化案例分析 锁消除 直接上代码 /** * 描述: 锁粒度演示 * @author karl * @create 2020-02-11 14:38 */ public class MySy ...
- DL4J之CNN对今日头条文本分类
一.数据集介绍 数据来源:今日头条客户端 数据格式如下: 6551700932705387022_!_101_!_news_culture_!_京城最值得你来场文化之旅的博物馆_!_保利集团,马未都, ...
- WinForm开发(2)——DataGridView控件(2)——C# dataGridview控件,怎么获取行数
dataGridView1.Rows.Count;//所有行数dataGridView1.RowCount;//可见行数
- leetcode 0215
目录 ✅ 1002. 查找常用字符 描述 解答 java other's implementation(todo watch me) cpp py ✅ 821. 字符的最短距离 描述 解答 cpp p ...
- 【PAT甲级】1050 String Subtraction (20 分)
题意: 输入两个串,长度小于10000,输出第一个串去掉第二个串含有的字符的余串. trick: ascii码为0的是NULL,减去'0','a','A',均会导致可能减成负数. AAAAAccept ...
- 研发2nm芯片,台积电如何做到天下第一?
日前,台积电宣布,正式启动2nm芯片工艺的研发,工厂将会设置在台湾新竹的南方科技园,预计2024年投入量产,发言人称:2nm工艺是一个重要节点,目标是比3nm制程缩小23%.科技先锋总会打脸分析专家, ...
- 解决:使用 swiper 自动轮播图片,当拖动过 swiper 内的内容时,导致不继续自动轮播
版本为1.3 当使用了 swiper 后: var mySwiper = new Swiper('.banner .swiper-container', { autoplay: 3000, loop: ...
- BigOps自动化运维安装以及所遇故障处理
本文参考官方文档进行安装,以及在安装中所遇到的问题呈现给大家.废话就不说了,开始安装.一.准备工作:本机系统环境是CentOS 7 x86 64位硬件配置建议物理内存8G+.CPU 4 cores+. ...
- iOS中统计平台的使用
iOS腾讯Bugly使用 https://www.jianshu.com/p/f672e0d202ef iOS 百度统计的使用技巧 https://blog.csdn.net/yy1992320/a ...