小W走迷宫

小W 走迷宫
【问题描述】
小W 被小M 困在了一个方格矩阵迷宫里,矩阵边界在无穷远处,我们做出如下的
假设:
a. 每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;
b. 走过的格子立即塌陷无法再走第二次;
c. 只能向北、东、西三个方向走。
小W 走了没多久就累坏了,他很想知道如果允许在方格矩阵上走 N 步,共有多少
种不同的方案。( 开始时小W 就在方格矩阵上的任意位置,2 种走法只要有一步不一样,
即被认为是不同的方案)
【输入格式】
一行输入N。
【输出格式】

一行输出方案个数。

/*
可以发现由于只有三个方向且不能回头,所以和位置并没有任何关系,那么就只和剩下的step和到达方向有关系,所以用num【i】【j】表示还剩下j步,且
通过i方向到达当前这一步。这样的时间复杂度是O(n*3)的;注意题目需要用高精度!!! 
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define N 10000
using namespace std;
int n;
bool vis[N][4];
int num[N][4][N],ans[N],as,tmp[N],len,nxt;
void dfs(int frm,int cal_dep)
{
	if(!cal_dep)
	{
		vis[cal_dep][frm]=1;num[cal_dep][frm][1]=1;num[cal_dep][frm][0]=1;
		int x=1;
		while(x<=as && ans[x]==9) x++;
		as=max(as,x);ans[x]++;
		for(int i=1;i<x;i++) ans[i]=0;
		return ;
	}
	for(int i=1;i<=3;i++)
	{
		if(i==(4-frm) && frm!=2) continue;
		if(!vis[cal_dep-1][i]) dfs(i,cal_dep-1);
		else //ans+=num[cal_dep-1][i];
		{
			len=1;nxt=0;
			while(len<=as || len<=num[cal_dep-1][i][0])
			{
				tmp[len]=(ans[len]+num[cal_dep-1][i][len]+nxt)%10;
				nxt=(ans[len]+num[cal_dep-1][i][len]+nxt)/10;
				len++;
			}
			if(nxt) tmp[len]=nxt;
			else len--;
			for(int j=1;j<=len;j++) ans[j]=tmp[j];as=len;
		}
		len=1;nxt=0;
		while(len<=num[cal_dep][frm][0] || len<=num[cal_dep-1][i][0])
		{
			tmp[len]=(nxt+num[cal_dep][frm][len]+num[cal_dep-1][i][len])%10;
			nxt=(nxt+num[cal_dep][frm][len]+num[cal_dep-1][i][len])/10;
			len++;
		}
		if(nxt) tmp[len]=nxt;
		else len--;
		for(int j=1;j<=len;j++) num[cal_dep][frm][j]=tmp[j];
		num[cal_dep][frm][0]=len;
	}
	vis[cal_dep][frm]=1;
}
int main()
{
//	freopen("game.in","r",stdin);
//	freopen("game.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=3;i++) dfs(i,n-1);
	for(int i=as;i;i--) printf("%d",ans[i]);
	return 0;
}
/*
当然还有第二种方法:
a[i] 记录走第i步是往北走的个数,b[i] 记录走第i步是往东或者者西时候的个数,c[i]=a[i]+b[i]。有以下递推式:
a[i]=a[i-1]+b[i-1]=c[i-1]
b[i]=2*a[i-1]+b[i-1]//如果上一步是向上走的那么当前这一步可以向东也可以向西,所以要乘2,但上一步是向东或向西,这不能反走,自能乘1 
则 c[i]=a[i]+b[i]=3*a[i-1]+2*b[i-1]=2c[i-1]+a[i-1]=2c[i-1]+c[i-2]。
直接高精度。
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define N 300000
using namespace std;
int n,nxt=0,len,lena,lenb,as;
int a[N],b[N],ans[N];
void cal()
{
	nxt=0;len=1;
	while(len<=lenb)
	{
		int tmp=b[len]*2+nxt;
		ans[len]=(tmp)%10;
		nxt=tmp/10;
		len++;
	}
	if(nxt) ans[len]=nxt;
	else len--;
	as=len;
	
}
void del()
{
	nxt=0;len=1;
	while(len<=lena || len<=as)
	{
	int tmp=a[len]+ans[len]+nxt;
	ans[len]=tmp%10;
	nxt=tmp/10;
	len++;
	}
	if(nxt) ans[len]=nxt;
	else len--;
	as=len;
	for(int i=1;i<=lenb;i++) a[i]=b[i];lena=lenb;
	for(int i=1;i<=as;i++) b[i]=ans[i];lenb=as;
}
int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d",&n);
	if(n<=2){
		printf("%d",(n==1?3:7));return 0 ;
	}
	a[1]=3;b[1]=7;lena=1;lenb=1;
	for(int i=3;i<=n;i++)
	{
		cal();del();
	}
	for(int i=as;i;i--) printf("%d",ans[i]);
	return 0;
 } 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值