您的位置:首页 > 其它

ZOJ 2563 Long Dominoes(状压DP)

2014-12-13 21:09 323 查看
给定一个m*n的方格子,要求用3*1的骨牌去覆盖,骨牌可以用横放或者竖放,问最终有多少种放置方式,将其铺满。

分析:由于最多30行,每行最多9列,所以可以按行来dp,设计每行的状态从而进行转移,考虑每个骨牌放置对下一行的影响,共有0,1,2,3种方式,0对应横放或者竖放时最下面那

个格子,此行对下一行没有影响,1,竖放时第1个,2竖放时第2个,这样进行转移。注意,第i行横放时要求上一行相应位置状态为0。

思路及代码都来自这里,其实不会做这题,看了才了解。

代码:

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <map>
#include <vector>
#define pb push_back
#define mp make_pair
#define esp 1e-14
#define lson   l, m, rt<<1
#define rson   m+1, r, rt<<1|1
#define sz(x) ((int)((x).size()))
#define pf(x) ((x)*(x))
#define pb push_back
#define in freopen("solve_in.txt", "r", stdin);
#define bug(x) printf("Line : %u >>>>>>\n", (x));
#define inf 0x0f0f0f0f
using namespace std;
typedef long long LL;
typedef map<LL, int> MPS;
typedef pair<LL, LL> PII;

const int M = (int)1e9 + 7;
const int maxn = 110;
const int maxm = 1111;

LL dp[maxn][23][maxm];
int n, m, c, d;
char maze[maxn][11];
int dig[11];

void getDig(int x) {
memset(dig, 0, sizeof dig);
int len = 0;
while(x) {
dig[len++] = x&1;
x >>= 1;
}
}
bool check(char *s, int x) {
for(int i = 0; s[i]; i++) {
if((x&1) && s[i] == '0') return false;
x >>= 1;
}
return true;
}
void dfs(int pre, int num, int st, int cur, int state, int cnt) {
if(cnt > d) return;
if(cur == m) {
dp[pre+1][cnt][state] = (dp[pre+1][cnt][state]+dp[pre][num][st])%M;
return;
}
if(maze[pre+1][cur] == '0') {
dfs(pre, num, st, cur+1, state, cnt);
} else if(dig[cur] == 0) {
if(cur+1 < m && dig[cur+1] == 0 && maze[pre+1][cur+1] == '1')
dfs(pre, num, st, cur+2, state, cnt);
if(pre+1 < n && maze[pre+2][cur] == '1')
dfs(pre, num, st, cur+1, state+(1<<cur), cnt);
dfs(pre, num, st, cur+1, state, cnt+1);
} else {
dfs(pre, num, st, cur+1, state, cnt);
}
}
int main() {

while(scanf("%d%d%d%d", &n, &m, &c, &d) == 4) {
memset(dp, 0, sizeof dp);
for(int i = 1; i <= n; i++)
scanf("%s", maze[i]);
dp[0][0][0] = 1;
for(int i = 0; i < n; i++) {
int j;
if(i == 0) {
j = 0;
getDig(j);
int x = 0;
if(dp[i][x][j])
dfs(i, x, j, 0, 0, x);
} else {
for(int j = 0; j < (1<<m);  j++) {
if(check(maze[i], j) == false) continue;
getDig(j);
for(int x = 0; x <= d; x++) if(dp[i][x][j])
dfs(i, x, j, 0, 0, x);
}
}
}
LL ans = 0;
for(int i = c; i <= d; i++)
ans = (ans + dp
[i][0])%M;
printf("%lld\n", ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: