POJ_2663_Tri Tiling_DFS,状态压缩,动态规划

今天看了星际穿越,真心碉堡了,目前为止看过最好的科幻电影


题意:

3*n的方格,用1*2的长方条铺满,有多少中方法。



Input

Input consists of several test cases followed by a line containing -1. Each test case is a line containing an integer 0 <= n <= 30.

Output

For each test case, output one integer number giving the number of possible tilings.


动归想了半天我靠。。。一直在想二维空间递推,即使知道想不出来了还是在想,其实用一维DP,讨论最后一列位置以及最后一列的情况(最后一列之前的全部填满),然后很简单就有了一个从i-1位置推到i位置的状态转移方法,但是这个状态有2^3种,其实这个题生写也还好,但是如果行数进一步扩大,就不行了。

所以说递推矩阵用DFS写,写了好久喔,好久不写搜索了喔,搜索王跟我不一队了喔,赶紧多练练喔。

特判n=0还写错了WA一次喔。


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int dfs(int loc,int x,int y,int tgt){
	if(loc==6){
		if(y==tgt)	return 1;
		return 0;
	}
	int ret=0;
	if(loc<3){
		if(x&(1<<loc))	return dfs(loc+1,x,y,tgt);
		if(tgt&(1<<loc))
			ret+=dfs(loc+1,x|(1<<loc),y|(1<<loc),tgt);
		if(loc<2&&!(x&(1<<(loc+1))))
			ret+=dfs(loc+1,(x|(1<<loc))|(1<<(loc+1)),y,tgt);
	}
	else{
		ret+=dfs(loc+1,x,y,tgt);
		if(loc<5&&!(y&(1<<(loc-3)))&&!(y&(1<<(loc-2)))&&(tgt&(1<<(loc-3)))&&(tgt&(1<<(loc-2))))
			ret+=dfs(loc+1,x,(y|(1<<(loc-3)))|(1<<(loc-2)),tgt);
	}
	return ret;
}
struct matrix{
	int a[10][10];
	matrix(){memset(a,0,sizeof(a));}
	matrix operator * (const matrix& in)const{
		matrix ret;
		for(int i=0;i<10;++i)
			for(int j=0;j<10;++j)
				for(int k=0;k<10;++k)
					ret.a[i][j]+=a[i][k]*in.a[k][j];
		return ret;
	}
	void set(){
		for(int i=0;i<8;++i)
			for(int j=0;j<8;++j)
				a[j][i]=dfs(0,i,0,j);
		for(int i=0;i<8;++i){
			a[i][0]-=a[i][3]+a[i][6];
			a[i][1]-=a[i][7];
			a[i][4]-=a[i][7];
		}
	}
	matrix quick_power(int n){
		if(n==1)	return *this;
		matrix tem=quick_power(n/2);
		if(n%2)	return tem*tem*(*this);
		return tem*tem;
	}
}trans,ans,b;
int n;
int main(){
	trans.set();
	memset(b.a,0,sizeof(b.a));
	b.a[7][0]=1;
	while(scanf("%d",&n)!=EOF&&n!=-1){
		if(!n){
			puts("1");
			continue;
		}
		ans=trans.quick_power(n)*b;
		printf("%d\n",ans.a[7][0]);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值