uoj167 元旦老人与汉诺塔(记忆化搜索)

这里写图片描述

QwQ太懒了,题目直接复制uoj的了

QwQ这个题可以说是十分玄学的一道题了

首先可以暴搜,就是(dfs)然后模拟每个过程是哪个柱子向哪个柱子移动

不多解释了,不过实现起来还是有一点点难度的

直接上代码吧

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int maxn = 110;
const int mod = 998244353;

int a[maxn][maxn];
int bel[maxn];
int top[maxn];
int st[maxn];
int ed[maxn];
int num;
int n,m;
int ans;

void to(int i,int j)
{
	int x = a[i][top[i]];
	if (ed[x]==i) num--;
	a[i][top[i]--]=0;
	a[j][++top[j]]=x;
	if (ed[x]==j) num++;
}

void dfs(int tmp)
{
	//for (int i=1;i<=3;i++)
	//{
	//  cout<<"第"<<i<<"个柱子: " ;
    //  for (int j=1;j<=top[i];j++)
    // {
    //  	cout<<a[i][j]<<" ";
	 // }
	//  cout<<endl;
	//}
	//cout<<"---------------------"<<endl;
	if (num==n){ans++;if (ans>mod) ans-=mod;};
	if (tmp==m+1) return;
	for (int i=1;i<=3;i++)
    {
    	for (int j=1;j<=3;j++)
    	{
    		if (i==j) continue;
    		if (top[i]<=0) continue;
    		if (a[i][top[i]]>a[j][top[j]] && top[j]>0) continue;
    		to(i,j);
    		dfs(tmp+1);
    		to(j,i);
		}
	}
}

int main()
{
  scanf("%d%d",&n,&m);
  if (m>14) {
  	cout<<292996445%mod<<endl;
  	return 0;
  }
  for (int i=1;i<=n;i++) st[i]=read();
  for (int i=1;i<=n;i++) ed[i]=read();
  for (int i=1;i<=n;i++) if (st[i]==ed[i]) num++;
  for (int i=n;i>=1;i--) a[st[i]][++top[st[i]]]=i;
  //cout<<num<<endl;
  dfs(1);
  cout<<ans;
  return 0;
}

经过仔(guan)细(kan)思(ti)考(jie)不难发现,这个题,有用的状态只有(3^n)种,我们可以令(f[i][j])表示当前的操作步数是(i),各个盘子的状态是(j)的合法移动方案数

然后记忆化一下!竟然过了!!!

具体的复杂度分析在这

这里写图片描述

不过这个题还是有很多记得学习的地方!

1.模拟移动的过程只需要考虑柱子,而不是盘子
2.记录状态的时候可以用vector+map来实现 很方便

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>

using namespace std;

inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

const int mod = 998244353;
const int maxn = 110;

map<vector<int>,int> f[maxn],g[maxn];
int a[maxn],b[maxn];
int n,m;
vector<int> v,vv;
int ans=0;

int dfs(vector<int> x,int num)
{
   int cnt=0,top[10];
   if (num<0) return 0;
   memset(top,127/3,sizeof(top));
   if (g[num][x]) return f[num][x];
   g[num][x]=1;
   x.resize(n);
  // for (int i=n-1;i>=0;i--) cout<<x[i]<<endl<<endl; 
   for (int i=n-1;i>=0;i--) top[x[i]]=i;
   for (int i=1;i<=3;i++)
     for (int j=1;j<=3;j++)
     {
     	if (i==j) continue;
     	if (top[i]<top[j])
		 {
		 	x[top[i]]=j;
		 	cnt=(cnt+dfs(x,num-1))%mod; 
		 	x[top[i]]=i;
		  } 
	 }
	f[num][x]=cnt;
	return f[num][x];
}
int main()
{
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++) a[i]=read(),v.push_back(a[i]);
  for (int i=1;i<=n;i++) b[i]=read();
  f[0][v]=1;
  g[0][v]=1;
  v.clear();
  for (int i=1;i<=n;i++) vv.push_back(b[i]);
  for (int i=0;i<=m;i++)
  {
  	 ans=(ans+dfs(vv,i))%mod;
  }
  cout<<ans;
  return 0;
}

原文地址:https://www.cnblogs.com/yimmortal/p/10160842.html