AcWing 4741. 魔法百合井

文章描述了一个关于魔法井的数学问题,井中含有多朵百合花,投入不同数量的硬币可以得到不同效果。通过动态规划的方法解决如何用最少的硬币收集所有百合花的问题。示例解释了两种不同情况的解决方案,并提供了C++代码实现。
摘要由CSDN通过智能技术生成

森林里有一口很深的魔法井,井中有 L 朵百合花。

你带着一个大空篮子和足够多的硬币来到了井边。

这个井有魔力,向里面投入硬币可以发生神奇的事情:

  • 如果你向井里一次性投入 1 个硬币,井就会发动魔法,将一朵百合花扔进你的篮子里。
  • 如果你向井里一次性投入 4 个硬币,井就会发动魔法,统计并记录到目前为止,已经扔进你的篮子里的百合花的数量。
  • 如果你向井里一次性投入 2 个硬币,井就会发动魔法,将等同于上次记录数量的百合花扔进你的篮子里。

有一点需要特别注意,如果你向井里一次性投入 11 个或 22 个硬币后,井中已经没有足够的百合花扔给你了,那么井就不会发动任何魔法,也不会扔给你任何百合花(钱白花了)。

请你计算,为了将所有百合花都收入篮中,所需要花费的最少硬币数量。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。

每组数据占一行,包含一个整数 L,表示井中百合花的总数量。

输出格式

每组数据输出一个结果,每个结果占一行。

结果表示为 Case #x: y,其中 x 为组别编号(从 1 开始),y为需要花费的最少硬币数量。

数据范围

1≤T≤100

1≤L≤105

输入样例:
2
5
20
输出样例:
Case #1: 5
Case #2: 15
样例解释

对于 Case 1,井中一共有 5 朵百合花。

最佳方案是一个接一个的连续向井中投入 5 个硬币,这样我们可以一个接一个的得到 5 朵百合花。

一共需要花费 5 个硬币。

对于 Case 2,井中一共有 15 朵百合花。

最佳方案为:

  • 首先,一个接一个的连续向井中投入 5 个硬币,这样我们可以一个接一个的得到 5 朵百合花。
  • 然后,我们一次性向井中投入 4 个硬币,这样井会记录下到目前为止扔进我们篮中的百合花数量为 5。
  • 最后,我们重复三次,每次向井中投入 2 个硬币,这样每次都可以得到 5 朵百合花,从而得到剩余的全部 15 朵百合花。

一共需要花费15 个硬币。


思路

典型的动态规划问题

根据最后一个问题的选择情况可将本问题划分为两种情况

1.最后一位选一的情况    f[i]=min(f[i],f[i-1]+1)

2.最后一位选2的情况   

分为选几个2

。。。。。4(截止目前为x)   2              2x=i

。。。。。4 2 2                                   3x=i

。。。。。4 2 2  ....2   (第k-1个2)       kx=i

所以x是i/k,相当于翻了k倍

后面部分是固定的,前面的x是变化的,使其取得最小值,即f[x]

第k个最小值

f[i*k]=min(f[i*k],f[i]+4+2*(k-1))

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N=100010;
int f[N];

int main()
{
    memset(f,0x3f,sizeof f);
    f[0]=0;
    for(int i=1;i<N;i++)
    {
        f[i]=min(f[i],f[i-1]+1);
        for(int j=2;j*i<N;j++)
        f[i*j]=min(f[i*j],f[i]+4+2*(j-1));
        
    }
    int T;
    cin>>T;
    for(int i=1;i<=T;i++)
    {
        int x;
        cin>>x;
        cout<<"Case #"<<i<<": "<<f[x]<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值