HihoCoder第九周 状态压缩 二 与POJ2411总结

23 篇文章 0 订阅

在此我向各位博友求助,特别想知道除了HihoCoder上面的结果要对1e9+7取余之外,这两道题还有什么其他的问题,都是骨牌覆盖问题,都是状态压缩+dp,为什么我能过poj2411的程序过不了HihoCoder,还不是其他诸如TimeLimited,而是Wrong Answer,这个问题我想了很久,还是不知道是怎么回事,如果有神通广大的博友知道答案,希望你能告诉我。顺便说一下,HihoCoder给的那个hint只看懂了一部分递推的公式,其中满足的那个条件还是不懂。

两个题目的连接地址:

http://hihocoder.com/problemset/problem/1048

http://poj.org/problem?id=2411

骨牌覆盖问题我想了很久很久,我自己也知道对于每一个位置上的骨牌来说,有三种可能,有可能是上楼的骨牌,有可能是下楼的骨牌,也有可能是同楼层的骨牌。但当时我思考的时候,就在想,比方说2*2这个位置。


有两种摆法,我当时就在想如何记录result[1][1]=2,因为这两种条件都满足了,所以result[1][1]=2?那之后的result[1][2]呢?

觉得这样不对。就完全没有思路了。

最后看了一个动态规划算法,但其实这道题算动态规划的话,我更觉得像枚举,枚举上楼的所有情况,枚举下楼的所有情况,看这两种情况里面,哪些合拍,之后才是动态规划记录其和的事。

首先觉得这种记录方法很棒,即记录两层楼的状态,如果是01代表竖着一个骨牌。如果是10代表,楼上的骨牌怎么来的不知道,但从楼下竖着一块牌是确定的。如果是11,说明都是横着的牌,所以楼上和楼下的下一张牌都要是1才能满足条件。如果是00,则GG。

之后就是第一层的初始化,只需记住1要成对出现就行了(因为这是第一层)。

被这题折磨太久,印象实在太深。希望交流。

#include <iostream>
#include <cstring>
using namespace std;

#define M 12

long long dp[12][1<<M];
int n,m;

int init_ok(int i)
{
	int count;
	for(count=m-1;count>=0;)
	{
		if((i>>count)&1)
		{
			if((i>>(count-1))&1)
			{
				count= count-2;
				continue;
			}
			else
			{
				count--;
				return 0;
			}
		}
		else
		{
			if(count==1&&(i&1))
				return 0;
			else
			{
				count--;
				continue;
			}
		}

	}
	return 1;
}

void init()
{
	int count;
	int kongjian = (1<<m)-1;

	memset(dp,0,sizeof(dp));

	for(count=0;count<=kongjian;count++)
	{
		if(init_ok(count))
			dp[0][count]=1;
	}
}

bool match(int a, int b)
{
	for (int i = 1; i < 1 << m;)
	{
		if (((a & i) == 0) && ((b & i) == 0))
			return false;
		if ((a & i) && (b & i))
		{
			if ((a & (i << 1)) && ((b & (i << 1))))
			{
				i <<= 2;
				continue;
			}
			else
				return false;
		}
		i <<= 1;
	}
	return true;
}

int main()
{

	while(scanf_s("%d %d",&n,&m),n &&m)
	{
		int i,shang,xia;
		if(n < m)
			i = n ,n = m,m =i;
		int kongjian = (1<<m)-1;

		init();

		for(i=1;i<n;i++)
		{
			for(xia = 0;xia<=kongjian;xia++)
			{
				for(shang=0;shang<=kongjian;shang++)
				{
					if(match(shang,xia))
						dp[i][xia]+=dp[i-1][shang];

				}
			}
		}

		cout<<dp[n-1][kongjian]<<endl;
	}

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值