题目描述
本题可以用状态压缩DP解答
用一个N位二进制数,每一位用0/1来表示有N个物品的组合中第i个物品的状态
因此可以循环1~2^N-1中的所有数来枚举它的全部状态
下面是我加了十分详细的注释的y总代码
代码主要分为两个部分(横着摆放的方式确定后,竖着摆放的方式就已确定):
-
枚举每一列合法的占位方式,记录在str数组内
(把连续空格数为奇数的状态设定为false,因为空格要摆放竖着的方块,单个空格无法摆放方块) -
开始DP
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 12, M = 1 << N;//M的每一位二进制位储存一种状态
int n, m;
long long f[N][M];
bool st[M];//储存每一列上合法的摆放状态
//f[i][j]表示摆放第i列,第i-1列向后伸出来横着的方格状态为j,的方案数,j为一个二进制数,用01表示是否戳出来
int main()
{
while (cin >> n >> m, n || m)
{
//枚举每一列的占位状态里哪些是合法的
for (int i = 0; i < 1 << n; i ++ )//一共n行,枚举n位不同的状态
{
int cnt = 0;//用来记录连续的0的个数
st[i] = true;//记录这个状态被枚举过且可行
for (int j = 0; j < n; j ++ )//从低位到高位枚举它的每一位
if (i >> j & 1)//如果为1
{
if (cnt & 1) st[i] = false;//如果之前连续0的个数是奇数,竖的方块插不进来,这种状态不行
cnt = 0;//清空计数器
}
else cnt ++ ;//如果不为1,计数器+1
if (cnt & 1) st[i] = false;//到末尾再判断一下前面0的个数是否为奇数,同前
}
memset(f, 0, sizeof f);//一定要记得初始化成0,对于每个新的输入要重新计算f[N][M]
f[0][0] = 1;
for (int i = 1; i <= m; i ++ )//对于每一列
for (int j = 0; j < 1 << n; j ++ )//枚举j的状态
for (int k = 0; k < 1 << n; k ++ )//再枚举前一行的伸出状态k
if ((j & k) == 0 && st[j | k])//如果它们没有冲突,i这一列被占位的情况也是合法的话
f[i][j] += f[i - 1][k];//那么这种状态下它的方案数等于之前每种k状态数目的和
cout << f[m][0] << endl;//求的是第m-1行排满,并且第m-1行不向外伸出块的情况
//0~m-1行是题目中可以摆方块的范围
}
return 0;
}
感谢评论中同学们指出的错误,现已更正
自己的一些理解:
https://www.acwing.com/solution/content/239291/
为什么st[j|k]那里用的是 j|k表示合法 没搞懂 j|k不应该是让二进制数上面更多位变成1了吗
你好,这步预处理中的st[]对应的列该怎么对应下去?比如st[1]是指第一列吗?
这里枚举的从0到n(0000,0001,0010,0011......)的所有状态的情况,对每一列都是适用的
st[i]=false可以直接break
写的好呀
写的好
写的很好
赞orz
cout << f[m][0] << endl;//求的是第m行排满,并且第m行不向外伸出块的情况
你好,请问你这里是不是有误,第m列应该已经在格子外了,格子内就是0~m-1列。最后f[m][0]表示的应该是第m-1摆满且外伸到第m列的横着方格数为0。你的所有理解都是往后一列,应该往前一列吧。
棋盘一共有
0~m-1
列f[i][j]
表示 前i-1列的方案数已经确定,从i-1列伸出,并且第i列的状态是j的所有方案数f[m][0]
表示 前m-1列的方案数已经确定,从m-1列伸出,并且第m列的状态是0的所有方案数也就是m列不放小方格,前m-1列已经完全摆放好
我写了详细的题解,你可以看看
我知道你说的意思啊,但是这位同学这个题解是不是写的正好往后一位了。
对的,
cout << f[m][0] << endl;
这一行代码注释有;有误。妙啊,看了你的注释才看明白
注释的很详细,一直不明白j的状态,看了你的f[m][0]的注释后秒懂
其实st数组存的也不算是合法的摆放状态,只是用来判断 j | k 的一个参考
最后输出的注释应该是m列排满,且n行均不伸出
感谢
dp中的第三个for循环的注释应该是 再枚举前一 “列” 的伸出状态吧
注释真详细~~