本文主要是介绍poj2411状压dp,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目
求把N*M的棋盘分割成若干个1*2的的长方形,有多少种方案。
例如当N=2,M=4时,共有5种方案。当N=2,M=3时,共有3种方案。
如下图所示:
输入格式
输入包含多组测试用例。
每组测试用例占一行,包含两个整数N和M。
当输入用例N=0,M=0时,表示输入终止,且该用例无需处理。
输出格式
每个测试用例输出一个结果,每个结果占一行。
数据范围
1≤N,M≤111≤N,M≤11
输入样例:
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0
输出样例:
1
0
1
2
3
5
144
51205
如果正常看的话很不好看那么就把每个1*2的方块沿着棋盘横向切开把它们变成1*1的所以每一行就分成了2*1的和1*1的这个1*1的有可能是和上一行也有可能是和下一行构成一个方块因此我们把行作为阶段1表示竖着的上部分0表示其他情况可能横可能竖然后就可以通过二进制来表示每一行的状态,然后上一行转移到下一行的条件就是1.上一行和下一行进行按位与运算之后的结果为0(假设上一行的一位是0那么下一行对应的位置是1,0都无所谓因为上一行的横块并不影响下一行,如果是1的话那么下一行必须是0如果下一行也是1的话那么它的竖块就拼不成了),2.上一行和下一行进行或运算的结果他的连续的0的数量必须是偶数(进行或运算之后表示为0的结果上一行的0表示竖着的块的下半块或者是横着的下一行表示是横着的如果是奇数的话就没法分割成这种横着的)。
初始化dp[0][0]=1,表示给他第一行之前给他堵死,终点dp[n][0]是因为第n行没法再存在1了;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=13;
long long dp[13][1<<N];
bool f[1<<N];
int m,n;
int main()
{while(cin>>n>>m&&n&&m){memset(dp,0,sizeof(dp));// memset(f,0,sizeof(f));for(int i=0;i<(1<<m);i++){int ans=0;for(int j=0;j<m;j++){if(i>>j&1){if(ans%2==1)break;elseans=0;}elseans++;}if(ans%2==1)f[i]=false;elsef[i]=true;}dp[0][0]=1;int maxx=0;for(int i=1;i<=n;i++){for(int j=0;j<(1<<m);j++){for(int k=0;k<(1<<m);k++){if((j&k)==0&&f[j|k])dp[i][j]+=dp[i-1][k];//maxx=max(maxx,dp[i][k]);//cout<<dp[i][j]<<' ';}}//cout<<endl;}cout<<dp[n][0]<<endl;}}
这篇关于poj2411状压dp的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!