【问题标题】:Coin change (coin values are powers of m)硬币变化(硬币值是 m 的幂)
【发布时间】:2016-01-24 20:40:27
【问题描述】:

以下问题是在比赛中(现在已经结束) 比赛link.

它似乎是经典硬币面额问题的变体 - 给定一个包含硬币值和数字 n 的数组(k 个元素)。我们需要回答可以计算 n 面额的方法的数量。我们可以通过DP 解决它,这将花费O(n*k) 时间。现在在比赛问题中,不是给出硬币值数组,而是有一个值 m,并且硬币值都是 m ex 的所有可能幂。 n= 200, m=3. 所以我们有[3^0, 3^1, 3^2, 3^3, 3^4] 的硬币值,更高的幂对于这个例子没有用]。

我在这里使用了DP 方法,但它提供了TLE。通过查看时间限制testcases<=10000n<=10000m<=10000,我假设我们必须在O(n) 时间内解决给定n,m 的问题[可能还需要优化这个。请帮我解决这个问题。 我使用DP的解决方案。

#include <bits/stdc++.h>
#include <stdio.h>

using namespace std;

int solve(vector<int>&vec, int n){
    cout<<"n= "<<n<<": m= "<<vec.size()<<endl;
    int r=n+1, c=vec.size()+1;
    vector<int>row(c,0);
    vector<vector<int> >dp(r, row);
    for(int i=0;i<c;i++)
        dp[0][i]=1;
    for(int i=1;i<r;i++){
        for(int j=1;j<c;j++){
            int a=0;
            if(i-vec[j-1]>=0)
                a=dp[i-vec[j-1]][j];
            dp[i][j]=a+dp[i][j-1];
        }
    }
    return dp[n][c-1];
}

int main()
{
    ios::sync_with_stdio(false);
    int tc,n,m;
    cin>>tc;
    while(tc--){
        cin>>n>>m;
        vector<int>temp;
        int index=0;
        temp.push_back(1);
        while(temp[index]*m<=n){
            temp.push_back(temp[index]*m);
            index++;
        }
        int result=solve(temp,n);
        cout<<result<<endl;
    }
    return 0;
}

【问题讨论】:

  • 与问题无关,但如果您包含来自 bits 的任何内容,则说明您做错了 - bits 包含 libstdc++ 的实现细节内容,不应该直接包含在内。跨度>
  • 您可能应该使用这样一个事实,即用硬币 m^0,m^1,m^2... 给出 n 总和的方法数与给 m*n 硬币 m^1,m^2,...

标签: c++ dynamic-programming partitioning combinatorics coin-change


【解决方案1】:

“硬币找零”和类似的分区问题通常从记忆中受益匪浅。我没有发现任何基于 m 次幂硬币值的聪明数学技巧可以击败具有记忆化的简单递归算法。
(在this answer 的相关问题中,我说明了记忆化对分区的影响算法更详细)

下面的 Javascript 代码示例解决了我的 i5 桌面上 n,m = 200,3 在 0.026 毫秒内的示例,以及 n,m = 10000,2 在 2.8 毫秒内的最坏情况;我不知道比赛的时间限制是多少,但是10000个随机案例大约需要3秒。 C++ 实现当然会快得多。

function coinPowers(n, m) {
    if (n < 1 || m < 1) return 0;
    if (n < m || m == 1) return 1;
    var power = Math.floor(Math.log(n) / Math.log(m));
    var memo = [];
    for (var i = 0; i < n; i++) memo[i] = [];
    return partition(n, m, power);

    function partition(n, m, power) {
        var count = memo[n - 1][power];
        if (count) return count;
        var coin = Math.pow(m, power), count = 1;
        for (var p = power; p > 0; coin /= m, p--) {
            if (coin < n) count += partition(n - coin, m, p)
            else if (coin == n) ++count;
        }
        return (memo[n - 1][power] = count);
    }
}

document.write(coinPowers(200, 3) + "<BR>");
document.write(coinPowers(200, 2) + "<BR>");
document.write(coinPowers(10000, 2) + "<BR>");

【讨论】:

    猜你喜欢
    • 2011-05-11
    • 2017-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-04
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多