zoj 1530 记忆化搜索

本文分享了一种使用记忆化搜索解决复杂问题的方法,并通过一个具体题目进行了实践演示。介绍了如何利用dp数组存储已计算的状态避免重复计算,提高搜索效率。

一直想做这样的题,果然做完之后有了些领悟,代码打得无比生疏,花了老长时间才过的~

刚开始也没神马思路,搜了搜解题报告,大多数都是爆搜,这样没有意思,后来找到了一篇用记忆化优化搜索做的,给力~

dp[i][k][j]:是否存在一个n位数,i位,以k数字大头,模n为j.值分0,1,2:若为0,不存在这样的数,值为1,上一位也就是第二位为0,值为2,上一位为1.

way[i][k][j]:状态与前一个对应,记录的是上一位的余数,前提是dp[i][k][j]>0

这样讲,如果我们用爆搜做此题,函数应该是dfs(i,k,j),那么dp[i][k][j]就是函数值,通过函数值可以推出上一次函数的k,而way[i][k][j]就是上一次函数的j。

#include <iostream>
#include <cstdio> 
#include <cstdlib>
#include <cstring>
#include <cmath>

#define N 105
#define ss(a) scanf("%d",&a)
#define cl(a) memset(a,0,sizeof(a))

using namespace std;

int dp[N][3][2*N],way[N][3][2*N],arr[N];

int main()
{
    int i,j,n;
    while (ss(n)!=EOF)
    {
          if (n==0) break;
          arr[1]=1;
          for (i=2;i<=100;i++) arr[i]=(arr[i-1]*10)%n;
          cl(dp);cl(way);
          dp[0][0][0]=1;
          for (i=1;i<=100;i++)
          {
              for (j=0;j<n;j++)
                  if (dp[i-1][0][j])
                  {
                        dp[i][0][j]=1;
                        way[i][0][j]=j;           
                  }
                  else if (dp[i-1][1][j])
                  {
                       dp[i][0][j]=2;
                       way[i][0][j]=j;
                  }
              for (j=0;j<n;j++)
              {
                  int t=(j+arr[i])%n;
                  if (dp[i-1][0][j])
                  {
                                    dp[i][1][t]=1;
                                    way[i][1][t]=j;
                  }
                  else if (dp[i-1][1][j])
                  {
                       dp[i][1][t]=2;
                       way[i][1][t]=j;
                  }
              }
              if (dp[i][1][0]) break;
          }  
          int a=1,b=0,p,q;
          for (j=i;j>=1;j--)
          {
              cout<<a;
              p=a;q=b;
              b=way[j][p][q];
              a=dp[j][p][q]-1;
          }
          cout<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值