zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    从零开始——PowerShell应用入门(全例子入门讲解)
    详解C# Tuple VS ValueTuple(元组类 VS 值元组)
    How To Configure VMware fencing using fence_vmware_soap in RHEL High Availability Add On——RHEL Pacemaker中配置STONITH
    DB太大?一键帮你收缩所有DB文件大小(Shrink Files for All Databases in SQL Server)
    SQL Server on Red Hat Enterprise Linux——RHEL上的SQL Server(全截图)
    SQL Server on Ubuntu——Ubuntu上的SQL Server(全截图)
    微软SQL Server认证最新信息(17年5月22日更新),感兴趣的进来看看哟
    Configure Always On Availability Group for SQL Server on RHEL——Red Hat Enterprise Linux上配置SQL Server Always On Availability Group
    3分钟带你了解PowerShell发展历程——PowerShell各版本资料整理
    由Find All References引发的思考。,
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10160842.html
Copyright © 2011-2022 走看看