棋盘 || 状压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 ...
随机推荐
- excel表格 筛选 通过mysql语句
1.整理excel表格的数据 类似的 前面有其他符号的 都可以处理. 注意下一步是2个操纵:分别设置左右: 结果: 2.在复制粘贴到excel的时候,会有一些数字被设置成了科学计数法, 例如复制到ex ...
- WCF全面解析之 第四讲 使用代码 部署服务
关键代码: ServiceHost host = null; //启动 private void button1_Click(object sender, EventArgs e) { host=ne ...
- lsof 查看打开了一个文件的有哪些进程 统计那个进程打开的文件最多
lsof | grep /lib64/libc-2.12.so | wc == 查看打开了一个文件的有哪些进程 lsof | awk '{print $2,$1}' | sort | uniq - ...
- XMPP详解
https://www.jianshu.com/p/84d15683b61e https://www.cnblogs.com/lurenq/p/7026983.html 1. xmpp简介 XMPP ...
- javascript数据类型及类型的转换总结
javascript 是浏览器客户端脚本语言,要想让网页与后台程序更好的交互效果,这里我们详细了解javascript 数据类型及类型的转换 1,数据类型 number number类型 数字类型,浮 ...
- 吴裕雄 PYTHON 神经网络——TENSORFLOW 正则化
import tensorflow as tf import matplotlib.pyplot as plt import numpy as np data = [] label = [] np.r ...
- 使用注解配置Servlet3.0
从Servlet3.0开始支持使用注解来配置. 注解只是代替了一部分的web.xml的 配置,通常在针对单个Servlet的配置时(比如Servlet的资源名称)使用注解 web.xml:优势在于解决 ...
- 【PAT甲级】1003 Emergency (25 分)(SPFA,DFS)
题意:n个点,m条双向边,每条边给出通过用时,每个点给出点上的人数,给出起点终点,求不同的最短路的数量以及最短路上最多能通过多少人.(N<=500) AAAAAccepted code: #in ...
- 大数据篇:YARN
YARN YARN是什么? YARN是一种新的 Hadoop 资源管理器,它是一个通用资源管理系统,可为上层应用提供统一的资源管理和调度,它的引入为集群在利用率.资源统一管理和数据共享等方面带来了巨大 ...
- Redis Set操作
public void CleanPur() { var typedClient = _redisClient.As<PurClass>(); typedClient.DeleteAll( ...