代码之家  ›  专栏  ›  技术社区  ›  Behl

陌生银行(ATCODER初学者竞赛099)

  •  0
  • Behl  · 技术社区  · 6 年前

    为增加取款难度,某银行在一次操作中只允许客户取款下列金额之一:

    1日元(日本货币)

    6日元,6日元 ^ 2(=36)日元,6 ^ 3(=216)日元,…

    9日元,9日元 ^ 2(=81)日元,9 ^ 3(=729)日元,…

    总共需要多少次操作才能提取N日元?

    取款的钱不准再存。

    约束条件 1≤N≤100000 n是一个整数。

    标准输入的输入格式如下:

    n 产量 如果至少需要X个操作才能总共提取N日元,请打印X。

    样本输入1 一百二十七 样本输出1 四 取1日元,9日元,36(=6 ^ 2)日元和81(=9 ^ 2)日元,我们可以在四次操作中撤回127日元。

    对我来说,这似乎是一个简单的贪心问题,这就是我使用的方法,但我发现我为一个样本得到了不同的结果,并得出结论。 它不会总是贪婪的。

    #include <iostream>
    #include <queue>
    #include <stack>
    #include <algorithm>
    #include <functional>
    #include <cmath>
    
    using namespace std;
    
    
    int intlog(int base, long int x) {
    return (int)(log(x) / log(base));
    }
    int main()
    {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    long int n;cin>>n;
    
    int result=0;
    while(n>0)
    {
    int base_9=intlog(9,n);int base_6=intlog(6,n);
    int val;
    val=max(pow(9,base_9),pow(6,base_6));
    //cout<<pow(9,base_9)<<" "<<pow(6,base_6)<<"\n";
    val=max(val,1);
    if(n<=14 && n>=12)
        val=6;
    n-=val;
    //cout<<n<<"\n";
    result++;
    }
    cout<<result;
    return 0;
    }
    

    在n 14和大于12时,我们必须选择6而不是9,因为要达到零,它将采取较少的步骤。

    只有18/22个TCS有交流电,请帮助我理解我的错误。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Roshan    6 年前

    贪婪不会在这里工作,因为贪婪地选择答案,即每一步的最佳结果都不能保证最好的最终结果(你可以在你的例子中看到)。因此,您应该在每个步骤中遍历所有可能的场景,以找出总体的最佳结果。

    现在让我们看看如何做到这一点。正如你所看到的,最大输入可以是10。 ^ 5。我们可以在一个操作中提取以下12个值中的任何一个。

    [1, 6, 9, 36(=6 ^ 2), 81(=9 ^ 2), 216(=6 ^ 3), 729(=9 ^ 3), 1296(=6 ^ 4), 6561(=9 ^ 4), 7776(=6 ^ 5), 46656(=6 ^ 6), 59049(=9 ^ 5)]

    因为6 ^ 7和9 ^ 6人将超过10万。

    所以每一步都有价值 n 我们将尽一切可能(即小于或等于 n )上面数组中的arr[i]元素,然后递归地解决 n-arr[i] 直到我们到达零点。

    solve(n)
     if n==0 
      return 1;
     ans = n;
     for(int i=0;i<arr.length;i++)
       if (n>=arr[i])
         ans = min(ans, 1+solve(n-arr[i]);
     return ans;
    

    现在这是一个非常耗时的递归解( O(n*2^12) )我们会尽量优化它。当您尝试使用一些示例案例时,您将知道子问题是重叠的,这意味着可能存在重复的子问题。下面是动态编程。您可以存储每个子问题的解决方案,以便将来可以重新使用它们。因此,我们可以修改我们的解决方案如下

    solve(n)
     if n==0 
      return 1; 
     ans = n;
     if(dp[n] is seen)
       return dp[n];
     for(int i=0;i<arr.length;i++)
       if (n>=arr[i])
         ans = min(ans, 1+solve(n-arr[i]);
     return dp[n] = ans;
    

    dp解决方案的时间复杂度为 O(n*12) ;