sgu132

5 篇文章 0 订阅
4 篇文章 0 订阅

132. Another Chocolate Maniac

time limit per test: 0.5 sec.
memory limit per test: 4096 KB

Bob really LOVESchocolate. He thinks he never gets enough. Imagine his joy when his parentstold him that they would buy him many rectangular chocolate pieces forhis birthday. A piece of chocolate is a 2x1 or 1x2 rectangle.Bob's parents also bought him a nice birthday cake, which can be imaginedas a matrix having M rows and N columns. Some positions onthe cake are occupied by candles, the others are empty. Bob's parents askedtheir son to place as many chocolate pieces as he can on the empty squareson the cake, in such a manner that no two chocolate pieces overlap. However,he would like to keep the chocolate pieces to himself. That's why, he wantsto place only a minimal amount of them on the cake and keep the rest. Inorder not to make Mon and Dad suspicious, Bob wants to place the chocolatepieces in such a way, that no other piece may be placed on the cake (thatis, there won't exist any two adjacent empty squares). Find the minimalnumber of pieces which need to be placed on the cake, so that they do notoverlap and no extra piece may be added.

Input

The first line ofthe input contains 2 integers: M (1<=M<=70)and N (1<=N<=7). Next, M lines will follow,each of them containing N characters, describing the cake. The characteron row i and column j of the cake may be either a '*'(ASCII code 42), representing a candle, or a'.' (ASCII code 46), representing an empty square.

Output

You should outputone integer: the minimal amount of pieces of chocolate which need to beplaced on the cake.

Sample Input

5 5
.*..*
*....
..**.
**.*.
.**..

Sample Output

4

题目大意:在一个N*M的矩阵中,有些位置不能放入巧克力,要求你放入尽可能少的1*2的巧克力,使得该矩阵中不能再放入巧克力.

题解:

看到那么小的N,那么熟悉的棋盘覆盖模型,状压DP很司空见惯了把.

也许有人会把这道题目跟上面的SGU131联系起来,有一点不同的地方就是,131是要把棋盘覆盖满,而132不用覆盖满,

131我们知道某一行的状态就可以直接知道它的上一行应该是什么状态,但是这道题目就不能这样.所以我们在要保存2维的状态,分别为这一行的状态和上一行的状态,

这样就可以避免后效性.

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int mn = 80,mm = 10,ms = 512,INF = 0x7FFFFFFF/2;
int f[2][ms][ms],n,m,i,j,k,t;
int a[mn],mi[10]={1};
char op[10];int tmpJ,tmpK;
void dfs(int p,int j,int k,int s,int cnt){
    //保证当前行的前两行不能放入2*1的巧克力
    if (p > 0 && ((k & mi[p-1]) == 0) && ((j & mi[p-1]) == 0)) return ;
    //保证当前行上一行不能放入1*2的巧克力
    if (p > 1 && ((k & mi[p-1]) == 0) && ((k & mi[p-2]) == 0)) return;
    //转移
    if (p == m){
	f[i & 1][k][s] = min(f[i & 1][k][s],f[1-(i&1)][tmpJ][tmpK]+cnt);
	return;
    }
    //什么都不放的状态
    dfs(p+1,j,k,s,cnt);
    //在当前行的上一行放入一个1*2的骨牌
    if (p < (m-1) && ((k & mi[p]) == 0) && ((k & mi[p+1]) ==0)) 
	dfs(p+1,j,k | mi[p] | mi[p+1],s,cnt+1);
    //在当前行的上一行放入一个2*1的骨牌,并影响到当前行
    if (((k & mi[p]) == 0) && ((s & mi[p])==0))
	dfs(p+1,j,k | mi[p],s | mi[p],cnt+1);
}
int main(){
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    scanf("%d %d\n",&n,&m);t = (1 << m)-1;
    for (i=1;i<=m;++i) mi[i] = mi[i-1] *2;//计算2的幂次,用来减少计算量
    for (i = 1;i<=n;++i){
	scanf("%s\n",op+1);
	for (j=1;j<=m;++j)
	    a[i] = a[i]*2+(op[j]=='*');
	/*
	 *读入每一行的不能覆盖的方案,二进制转十进制保存
	 *不能放为1,能放为0
	 */
    }
    /*
     *初始化
     */
    for (j = 0;j<=t;++j)
	for (k=0;k<=t;++k) f[0][j][k] = INF;
    f[0][t][a[1]] = 0;
    /*
     *动归过程
     */
    for (i = 1;i<=n;++i){
	//初始化
	for (j=0;j<=t;++j)
	    for (k=0;k<=t;++k)
		f[i & 1][j][k] = INF;
	//枚举当前行前两行的状态
	for (j=0;j<=t;++j)
	    for (k=0;k<=t;++k)
		if (f[1 - (i & 1)][j][k] != INF) {
		    tmpJ = j,tmpK = k,dfs(0,j,k,a[i+1],0);
		}
    }int ans = INF;
    for (i = 0;i<=t;++i)
	ans = min (ans,f[n & 1][i][0]);
    printf("%d\n",ans);
    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值