题目:http://acm.hdu.edu.cn/showproblem.php?pid=4804
题意:给你一个n*m的棋盘,让你用1x1和1x2的方块填满它,棋盘有些地方不能放方块,1x1的方块使用有限制,问一共有多少种方法填满
dp多开一维存放1x1的个数,之后就是正常的插头dp思路
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> using namespace std; const int mod=1e9+7; int dp[2][22][1<<10]; int a[105][15]; int main() { int n,m,c,d; int now=0,pre=1; while(scanf("%d%d%d%d",&n,&m,&c,&d)!=EOF) { int tot=1<<m; memset(a,0,sizeof(a)); for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%1d",&a[i][j]); memset(dp[now],0,sizeof(dp[now])); dp[now][0][tot-1]=1; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { swap(now,pre); memset(dp[now],0,sizeof(dp[now])); if (a[i][j]) { for(int k=0;k<=d;k++) for(int st=0;st<tot;st++)//枚举轮廓线的状态 { if (k&&(st>>j&1)) dp[now][k][st]=(dp[now][k][st]+dp[pre][k-1][st])%mod;//1x1 if (j&&(st>>j&1)&&!(st>>(j-1)&1)) dp[now][k][st|1<<(j-1)]=(dp[now][k][st|1<<(j-1)]+dp[pre][k][st])%mod;//横放1x2 dp[now][k][st^1<<j]=(dp[now][k][st^1<<j]+dp[pre][k][st])%mod;//竖放1x2 } } else { for(int k=0;k<=d;k++) for(int st=0;st<tot;st++) if (st&1<<j) dp[now][k][st]=(dp[now][k][st]+dp[pre][k][st])%mod;//不能放 } } } int ans=0; for(int i=c;i<=d;i++) ans=(ans+dp[now][i][tot-1])%mod; printf("%d\n",ans); } return 0; }
时间: 2024-10-14 17:07:54