Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 12042 | Accepted: 7011 |
Description

Expert as he was in this material, he saw at a glance that he'll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won't turn into a nightmare!
Input
Output

Sample Input
1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0
Sample Output
1 0 1 2 3 5 144 51205
Source
覆盖模型,用状压dp解决
设棋盘为n, m为了高效起见,如果n > m,就交换,如果n, m都是奇数,答案一定是0(无论放多少牌,牌所占的空间是偶数的,所以最后的空间一定是偶数才能放满
dp[0][(1<<m)-1] = 1;
dp[i][j] += dp[i - 1][k];
其中的j和k是符合条件的状态,我们通过dfs预处理出来(把上一行和这一行的状态和在一起看做一个状态)
放置方案有3种,竖放,横放,不放(0) 如果当前行当前列为0(二进制表示状态),那么当前列上一行一定是1(否则就空出2个位置来了);如果当前行当前列为1, 那么可能是竖放,则上一行当前列是0;可能是横放,则当前行下一列是1,上一行当前列是1,上一行下一列是1
为什么竖直放置要看做01呢,这样可以保证最后一行一定全部是1
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
__int64 dp[12][2100];
struct node
{
int cur, last;
}s[14000];
int n, m, res;
void dfs(int l, int cur, int last)
{
if (l > m)
{
return ;
}
if (l == m)
{
s[res].cur = cur;
s[res++].last = last;
return;
}
dfs(l + 2, (cur << 2) | 3, (last << 2) | 3);
dfs(l + 1, (cur << 1) | 1, last << 1);
dfs(l + 1, (cur << 1), (last << 1) | 1);
}
int main()
{
while (~scanf("%d%d", &n, &m))
{
if (!m && !n)
{
break;
}
if( (m & 1) && ( n & 1) )
{
printf("0\n");
continue;
}
if (n < m)
{
m ^= n;
n ^= m;
m ^= n;
}
res = 0;
dfs(0, 0, 0);
memset (dp, 0, sizeof(dp) );
dp[0][(1 << m) - 1] = 1;//作为初始化,第0行只能横放,因为不能影响下面;
for (int i = 1; i <= n; ++i)
{
for (int j = 0; j < res; ++j)
{
dp[i][s[j].cur] += dp[i - 1][s[j].last];
}
}
printf("%I64d\n", dp[n][(1 << m) - 1]);
}
}