题目大意
给定一个N*M大小的大小的蛋糕,蛋糕的有些地方已经放置了东西,要求你在蛋糕上放入尽量少的1*2大小的巧克力,使得蛋糕不能够再放入巧克力
题解
和POJ1038恰好相反,此题是放入尽量少的巧克力,根据前两行的状态来进行当前行的放置,用dfs来进行三行的状态枚举,并同时检查放置是否合法,放完m列之后就可以进行状态转移了
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MAXN 130 #define INF 0x3f3f3f3f int dp[2][MAXN][MAXN]; int n,m,s[75]; bool check(int step,int x,int y) { if(step>=1&&!(x&(1<<(step-1)))&&!(y&(1<<(step-1)))) return false; if(step>=2&&!(x&(1<<(step-1)))&&!(x&(1<<(step-2)))) return false; return true; } void dfs(int sum,int i,int x,int y,int st,int step) { if(!check(step,x,y)) return; if(step==m) { dp[i][st][x]=min(dp[i][st][x],sum); return; } if(!(x&(1<<step))&&!(st&(1<<step))) dfs(sum+1,i,x|(1<<step),y,st|(1<<step),step+1); if(step+2<=m&&!(x&(1<<step))&&!(x&(1<<(step+1)))) dfs(sum+1,i,x|(1<<step)|(1<<(step+1)),y,st,step+2); dfs(sum,i,x,y,st,step+1); } int main() { scanf("%d%d",&n,&m); char str[15]; memset(s,0,sizeof(s)); for(int i=1; i<=n; i++) { scanf("%s",str); int len=strlen(str); for(int j=0; j<len; j++) s[i]|=(str[j]=='*'?1:0)<<j; } memset(dp,INF,sizeof(dp)); dp[1][s[1]][(1<<m)-1]=0; for(int i=2; i<=n+1; i++) { memset(dp[i&1],INF,sizeof(dp[i&1])); for(int j=0; j<(1<<m); j++) for(int k=0; k<(1<<m); k++) if(dp[(i+1)&1][j][k]!=INF) dfs(dp[(i+1)&1][j][k],i&1,j,k,s[i],0); } int ans=INF; for(int i=0; i<(1<<m); i++) ans=min(ans,dp[(n+1)&1][0][i]); printf("%d ",ans); return 0; }