51nod-1033 骨牌覆盖 V2

51nod-1033 骨牌覆盖 V2_第1张图片

地址:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1033

思路:状态压缩DP+矩阵快速幂

对于每行最多只有5列,因此可以枚举出它们的全部状态 0->(1<

1.由于是1X2的骨牌,则二进制数11,110是合法的,1,10是不合法的,那么其合法的状态只有d{0,3,6,12,15,24,27,30}

2.对于第i行的状态只与第i-1行的状态有关,那么对于第i-1行的状态a中二进制位为0的就必须要在第i行的状态b中补上,

例如a=5(101) 那么b=3(11)是合法的, b=1是不合法的,因为b=1,101和001是不可以将中间的0给补上,而b=3则是将 2*1的骨牌插在中间,因此对于第i行状态b来说 a|b=(1<

3.同时 a&b必须在合法状态中才行,因为a&b表示第i行的1*2的骨牌的摆放状态,例如 二进制 a=1011,b=1110,这时 a&b=1010而此时的骨牌是没法摆放的

4.那么此时就可以写出状态压缩DP了

		dp[1][0]=dp[1][3]=dp[1][6]=dp[1][12]=dp[1][15]=dp[1][24]=dp[1][27]=dp[1][30]=1;
		int s=(1<

时间复杂度为 O(n*pow(2,5)*pow(2,5))是肯定超时的

而我们对转移方程观察发现

dp[i][j]只与 dp[i-1][k]有关,而对于判断条件 if((j|k)==s&&d[j&k]) 也是固定的

那么就可以用矩阵快速幂来优化.

 

Code  状态压缩DP版本:

#include
#include
using namespace std;

const int MOD=1e9+7;
const int MAX_N=1005;
int n,m;
bool d[35];
int dp[MAX_N][35];

int main()
{
	ios::sync_with_stdio(false);
	d[0]=d[3]=d[6]=d[12]=d[15]=d[24]=d[27]=d[30]=1;
	while(cin>>n>>m){
		memset(dp,0,sizeof(dp));
		dp[1][0]=dp[1][3]=dp[1][6]=dp[1][12]=dp[1][15]=dp[1][24]=dp[1][27]=dp[1][30]=1;
		int s=(1<

 

Code  状态压缩DP+矩阵快速幂优化:

#include
#include
using namespace std;
typedef long long LL;

const int MOD=1e9+7;
const int MAX_S=35;
struct Matrix{
	LL a[MAX_S][MAX_S];
	Matrix (){	memset(a,0,sizeof(a));}
	Matrix operator*(const Matrix &A){
		Matrix B=Matrix();
		for(int k=0;k>n>>m){
		int s=(1<>=1;
		}
		cout<

 

你可能感兴趣的:(51Nod,DP,状态压缩DP,矩阵快速幂)