2018-9-12【训练日记】

  昨天和今天看了三篇关于数位dp的博文,其中有一篇涉及的几乎全是深搜,再学一下深搜吧:

模板一:

int search(){
    for(int i=1;i<=算符种数;i++){
        if(满足条件){
            保存结果;
            if(到目的地)输出解;
                else search(k+1);
            恢复:保存结果之前的状态;{回溯一步}
        }
    }
}

模板二:

int search(){
    if(到目的地)输出解;
    else

        for(int i=1;i<=算符种数;i++){
            if(满足条件){
                保存结果;
                search(k+1);
                恢复:保存结果之前的状态;{回溯一步}
            }
        }
}

深搜的典型例题:

素数环:

从1-20这20个数摆成一个环,要求相邻的两个数的和是一个素数。

思路:

从1开始,每个空位有20 种可能,只要填进去的数合法,与前面的数不相同,与左边相邻的数的和是一个素数,第20个数还要判断和第一个数的和是否素数。

1,数据初始化;

2,递归填数:判断第i个数填入是否合法;

   1》如果合法,填数;判断是否达到目标(20个已经填完):是,打印结果;不是,递归填下一个,

   2》如果不合法,选择下一种可能。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
bool b[21]={0};
int total=0,a[21]={0};
int search(int);//回溯过程
int print();    //输出方案
bool pd(int,int);//判断素数
int main(){
    search(1);
    cout<<total<<endl;//判断总方案数
}
int search(int t){
    int i;
    for(i=1;i<=20;i++){//有20个数可选
        if(pd(a[t-1],i)&&(!b[i]))//判断与前一个数是否构成素数以及该数是否可用
        {
            a[t]=i;
            b[i]=1;
            if(t==20){if(pd(a[20],a[1]))print();}
            else search(t+1);
            b[i]=0;
        }
    }
}
int print(){
    total++;
    cout<<"<"<<total<<">";
    for(int j=1;j<=20;j++){
        cout<<a[j]<<" ";
    }
    cout<<endl;
}
bool pd(int x,int y){
    int k=2,i=x+y;
    while(k<=sqrt(i)&&i%k!=0)k++;
    if(k>sqrt(i))return 1;
    else return 0;
}

我说的是这篇博文:https://blog.csdn.net/wust_zzwh/article/details/52100392,讲的应该算是不错,不过他给的思路和代码我有点串不起来,应该是我自身的原因,问题应该是关于limit的限制那里,本周训练的第二题也是,已经找到规律了,就是写不出来,网上也没有题解,太难受了简直;关于第二篇博文:https://blog.csdn.net/zhangxian___/article/details/75304335,博文不长,只讲了一个问题,没有62和4,讲得很细致,很好,就是排版有点乱,特别喜欢他说的:

我们设一个数组f[i][j],表示i位数,最高位是j的数,符合题意的数有多少个。
比如f[1][2]=1; f[1][4]=0; f[2][6]=8 (60,61,63,64,65,66,67,68,69).

我们先不关注这个f有什么用,我们先关注f本身怎么求。首先
f[1][i]=0(if i==4),f[1][i]=1(if i!=4) (0<=i<=9)。
这一步是很显然的,那么根据这个题的数据范围,只需要递推到f[7][i]就够用了。
那么稍微理解一下,可以想出递推式:
  f[i][j]=
    if (j==4) f[i][j]=0
    else if (j!=6) f[i][j]=Σf[i-1][k] (k=0,1,2,3,4,5,6,7,8,9)
        else if (j==6) f[i][j]=Σf[i-1][k] (k=0,1,3,4,5,6,7,8,9)

上面的式子也是很显然的,如果觉得不显然可以这样想:i位数,最高位是j的符合条件的数,
如果j是4,肯定都不符合条件(因为题目不让有4),所以直接是0;如果j不是6,
那么它后面随便取,只要符合题意就可以,所以是f[i-1][k],k可以随便取的和;
如果j是6,后面只要不是2就行,所以是f[i-1][k],k除了2都可以,求和。

这代码简直太直观了,配上文字,外循环,内循环,原因及结果,都清楚了,上一篇的这道题目时关联了它上面的题目,一道题看不懂,道道题都看不懂,太难受了。

最近在看的题目是那个,N=12 =+1-2+3-4+5-6+7-8+9-1+0-1+1-1+2;,来回写了几排,129和29,拆开来看,有一部分的加减项目,和29是重合的,1129就和129有一部分是重合的,的确是按位来的,就是写不出来,也没有题解,应该是挺简单的吧,我不会判断当前项是由前面几项相加时的相加步数问题,可能也就是第一篇博文里看不懂的“limit”问题。

猜你喜欢

转载自blog.csdn.net/sodacoco/article/details/82670181