P1077 [NOIP2012 普及组] 摆花

27 篇文章 1 订阅

在这里插入图片描述
在这里插入图片描述
这是我差不多是第一次从暴力递归优化到记忆化搜索,期间经历了一定的曲折。
解题过程:
1.看到这个题首先能够想到,每次摆花,可以选择和前面一样的花(如果前面的花还有剩余的话),也可以选择摆下一种花,于是最初的暴力递归算法就出来了。此方法提交有30分。

#include<bits/stdc++.h>
#define MAX 101
using namespace std;
int n,m;
int num[MAX];//第i种花的数量
int res=0;
int sum(int temp)
{
    //剩余所有花的数量
    int all=0;
    for(int i=temp;i<n;i++)
    {
        all+=num[i];
    }
    return all;
}
void fun(int index,int temp)//temp表示花的编号
{
    if(index>=m)
    {
        res+=1;
        res%=(1000007);
        return;
    }
    if(temp>=n||n-index>sum(temp))//如果当前选择花的序号已经超过了种类数,那么就停止
    {
        return;
    }
    if(num[temp]>0)
    {
        num[temp]-=1;
        fun(index+1,temp);
        num[temp]+=1;//注意回溯
    }
    fun(index,temp+1);
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        cin>>num[i];
    }
    fun(0,0);
    cout<<res<<endl;
    return 0;
}

2.将上述的暴力递归改为记忆化搜索,按照之前写的方法进行改动。提交后发现只有10分,原因在于:这里的变量还应该包含第temp种花的数量,因为前面使用到了回溯,记忆化之后无法将变量返回,所以要把这个变量也当成一个参数传入。得到第三个代码。

#include<bits/stdc++.h>
#define MAX 101
using namespace std;
int n,m;
int num[MAX];//第i种花的数量
int res=0;
int arr[MAX][MAX];
void init()
{
    for(int i=0;i<MAX;i++)
    {
        for(int j=0;j<MAX;j++)
        {
            arr[i][j]=-1;
        }
    }
}
int sum(int temp)
{
    //剩余所有花的数量
    int all=0;
    for(int i=temp;i<n;i++)
    {
        all+=num[i];
    }
    return all;
}
int fun(int index,int temp)
{
    if(arr[index][temp]!=-1)
    {
        return arr[index][temp];
    }
    if(index>=m)
    {
        arr[index][temp]=1;
        return arr[index][temp];
    }
    if(temp>=n||n-index>sum(temp))
    {
        arr[index][temp]=0;
        return arr[index][temp];
    }
    int ways = 0;
    if(num[temp]>0)
    {
        num[temp]-=1;
        ways+=fun(index+1,temp);
        num[temp]+=1;
    }
    ways+=fun(index,temp+1);
    arr[index][temp]=ways;
    return arr[index][temp];
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        cin>>num[i];
    }
    init();
    int ways = fun(0,0);
    cout<<ways-2<<endl;
    return 0;
}

3.将第temp种花的数量传入之后得到以下代码,注意方法要取余,不然只有50分:

#include<bits/stdc++.h>
#define MAX 102
using namespace std;
int n,m;
int num[MAX];//第i种花的数量
int res=0;
int arr[MAX][MAX][MAX];
void init()
{
    for(int i=0;i<MAX;i++)
    {
        for(int j=0;j<MAX;j++)
        {
            for(int k=0;k<MAX;k++)
            {
                arr[i][j][k]=-1;
            }

        }
    }
}
int sum(int temp,int num_temp)
{
    //剩余所有花的数量
    int all=num[temp]-num_temp;
    for(int i=temp+1;i<n;i++)
    {
        all+=num[i];
    }
    return all;
}
long long fun(int index,int temp,int num_temp)//num_temp表示使用了第temp号花多少盆
{
    if(arr[index][temp][num_temp]!=-1)
    {
        return arr[index][temp][num_temp];
    }
    if(index>=m)
    {
        arr[index][temp][num_temp]=1;
        return arr[index][temp][num_temp];
    }
    if(temp>=n||(n-index)>sum(temp,num_temp))//超过了n种花或者剩余所有花的总数都比要摆的花小
    {
        arr[index][temp][num_temp]=0;
        return arr[index][temp][num_temp];
    }
    long long ways = 0;
    if(num[temp]-num_temp>0)
    {
        ways+=(fun(index+1,temp,num_temp+1)%1000007);
        //num[temp]+=1;
    }
    ways+=(fun(index,temp+1,0)%1000007);
    ways%=1000007;
    arr[index][temp][num_temp]=ways;
    return arr[index][temp][num_temp];
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
    {
        cin>>num[i];
    }
    init();
    long long ways = fun(0,0,0);
    cout<<ways<<endl;
    return 0;
}

在这里插入图片描述
总结一下就是:要将所有的变量找齐,判断是哪些值在影响答案变化。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值