欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

有关递归

程序员文章站 2022-07-13 11:35:54
...

p1478陶陶摘苹果https://www.luogu.org/problemnew/show/P1478

题意:苹果树上的每个苹果,会告诉苹果的高度已经主人摘它需要的最大力气。a是板凳高度,b是陶陶能伸的最大高度。题目告诉了开始时陶陶的力气s,求最多能摘多少苹果。

这道题解题方法之一是采用回溯法:我们不难发现,对于那些不能够采到的苹果,我们搜索它们只会白白浪费时间,那我们就可以将这些苹果排除掉,这样就使得搜索子树被缩小了。这就是剪枝。我们可以将所有的苹果按照高度从矮到高排序。在这种情况下当我们搜索到一个够不到的苹果时,无论我们再往下搜索多久,我们都不会再搜索到可以够得到的苹果了。这时候我们就可以return 0 了。

就会发现在输出的每次调用的函数中,有很多次调用的num和rest是相同的,这就说明我们做了很多无用功。那么怎么优化呢?这时候记忆化搜索就闪亮登场了:

所谓记忆化搜索,就是将每个不同参量的函数的返回值存在一个数组里,当再次调用这个函数的时候,就不用再次费时间计算这个函数的返回值了

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int n,s;//苹果树数目,力气s
int a,b;//椅子告诉a,淘淘手伸直的最大高度b
//int x[5005],y[5005];//苹果树高度,需要力气
int vis[5005][1001],mem[5005][1001];//vis存储是否访问过调用这两个参量的函数,mem存储调用这两个参量的函数的返回值
struct apple
{
   int xi,yi;
}ap[5005];
bool cmp(apple x,apple y)
{
    return x.xi<y.xi;
}
int dfs(int index,int rest)
{
    if(index>=n||ap[index].xi>a+b||rest<=0)//当搜索到碰不到的苹果,就不用继续往下了
        return 0;
    if(vis[index][rest])
        return mem[index][rest];
    vis[index][rest]=1;
    int maxx=dfs(index+1,rest);
    if(ap[index].xi<=a+b&&rest>=ap[index].yi)
    {
        int t=dfs(index+1,rest-ap[index].yi)+1;
        maxx=t>maxx?t:maxx;
    }
    return mem[index][rest]=maxx;//先赋值再返回maxx

}
int main()
{
    scanf("%d%d",&n,&s);
    scanf("%d%d",&a,&b);
    for(int i=0; i<n; i++)
    {
        scanf("%d%d",&ap[i].xi,&ap[i].yi);
    }
    sort(ap,ap+n,cmp);

    cout<<dfs(0,s)<<endl;
    return 0;
}

p1149火柴棒等式https://www.luogu.org/problemnew/show/P1149

题意:给出n,代表总的火柴数目,求满足条件的'A+B=C’的有多少种。其中‘+‘和'-'就要花费4根火柴。

思路:这道题要采用回溯法,我开始对于大于10的数的火柴数目不知道怎么求,后来参考,a[i]=a[i%10]+a[i/10];这是一个很巧妙的写法。在写dfs的时候,要注意退出条件,就是tot>2时,说明已经选了3个了。在每一次循环时,要先判断n-a[i]是否大于等于0,如果小于了,则火柴数目不够。还要注意回溯。回到上一个状态。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int n,ans=0,b[4];
int a[1005]={6,2,5,5,4,5,6,3,7,6};
// a[0]=6,a[1]=2,a[2]=5,a[3]=5,a[4]=4,a[5]=5,a[6]=6,a[7]=3,a[8]=8,a[9]=6;
 void dfs(int tot)//sum代表选择火柴的总根数
 {
     if(tot>2)
        return;
     for(int i=0;i<=1000;i++)
     {

         //n=n-a[i];
         if(n-a[i]>=0)
         {

             b[tot]=i;
              n=n-a[i];
             if(tot==2)
             {
                 if(b[0]+b[1]==b[2]&&n==0)
                 {
                     ans++;
                     //return;
                 }
             }
             else
                dfs(tot+1);
             n=n+a[i];
         }
     }

 }
int main()
{


    cin>>n;
    n-=4;
   // dfs(0,0,0);
    for(int i=10;i<=1000;i++)
    {
        a[i]=a[i%10]+a[i/10];
    }
    dfs(0);
    cout<<ans<<endl;
    return 0;
}

p1036选数https://www.luogu.org/problemnew/show/P1036

从n个数中选k个数,只要k个数的和为素数,即满足条件,求满足条件(和为素数)的一共有多少个

解答:就是用dfs,注意循环条件和退出条件,关键部分我参考了别人的,我自己还是不会写,我太low了吧 

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define ll long long
//const int maxn=5e6+5;
int a[25];
int vis[25];
ll ans=0;
int n,k;
bool isPrime(ll num)
{
                 //两个较小数另外处理
                 if(num ==2|| num==3 )
                                 return 1 ;
                 //不在6的倍数两侧的一定不是质数
                 if(num %6!= 1&&num %6!= 5)
                                 return 0 ;
                 int tmp =sqrt( num);
                 //在6的倍数两侧的也可能不是质数
                 for(int i= 5;i <=tmp; i+=6 )
                                 if(num %i== 0||num %(i+ 2)==0 )
                                                 return 0 ;
                 //排除所有,剩余的是质数
                 return 1 ;
}
void dfs(int step,int sum,int cnt)
    {
        if(step==n||cnt==k)  //如果已经进行到了n+1次,或者是已经选了k个数
        {
            if(isPrime(sum) && cnt==k)  //如果sum为一个素数且已经选了k个数
                ans++;  //总方案书+1
            return;  //返回
        }
        dfs(step+1,sum+a[step],cnt+1);  //继续搜索,选择下一个数
        dfs(step+1,sum,cnt);  //继续枚举不选择下一个数的情况
        return;
    }

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    dfs(0,0,0);
    cout<<ans<<endl;
    return 0;
}

 

上一篇: 有关python

下一篇: 有关xss