题意:给出一个M * N的矩阵,用1*2的方块去覆盖。但是有一些位置有花花草草,是没法放方块的。求不覆盖花花草草且把矩阵全用方块覆盖的方案数。
思路:图论上的完美覆盖问题。求出完美覆盖的个数。可以利用状态压缩DP来求解。
我们从最左上方的格子开始覆盖,这样我们放方块的方法就是两种:覆盖当前格子右边的横着放,覆盖当前行的下一行的竖着放(有这个顺序非常重要,这样就可以DP按照顺序去求解)。然后就枚举所有的情况,判断是否是合法的覆盖。但是这样朴素的做法一定会超时,我们要去优化。
设要在(i,j)格子上放置方块,由于总是从最左上方开始放置的,则对于(i' ,j') < (i,j)总可以保证(i',j')已经放完。同时,由于方块的大小为1*2,那么,对于满足
(i',j') >=(i,j)且除了最小的i'之外 的格子,一定是没有被覆盖的。所以,其实真正的不确定的只有每列还没有查询的格子最上面的一个,一共m个。则这m个可以通过状态压缩来编码进行记忆化搜索。
另一个思路:前面已经说到这是图论中的完美匹配,所以我们可以利用图论完美匹配的解法去解这道题。因为上一个思路是指数级的复杂度,所以在很大的图中是不适用的,那这个思路就提供了很好的方法。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1000000007;
const int MAX = 15;
int M,N,K;
int dp[1<<MAX];
int res[1<<MAX];
bool f[MAX][MAX];
int main(void)
{
//freopen("input.txt","r",stdin);
while(scanf("%d %d %d", &N,&M,&K) != EOF){
memset(f,false,sizeof(f));
memset(res,0,sizeof(res));
memset(dp,0,sizeof(dp));
for(int i = 0 ; i < K; ++i){
int x,y;
scanf("%d %d", &x, &y);
f[x][y] = true;
}
res[0] = 1;
for(int i = N-1 ; i >=0; --i){
for(int j = M-1 ; j >=0 ;--j){
for(int s = 0; s < (1<<M); ++s){
if((s & (1 << j)) || f[i][j])
dp[s] = res[s &(~(1 << j))];
else{
int ans = 0;
if(j+1 < M && !f[i][j+1] && !(s & (1<<(j+1))))
ans = (ans + res[s | (1 << (j+1))]) % MOD;
if(i+1 < N && !f[i+1][j])
ans = (ans + res[s | (1 << j)]) % MOD;
dp[s] = ans;
}
}
swap(dp,res);
}
}
printf("%d\n",res[0]);
}
return 0;
}