硬币变化(硬币值是m的幂)

时间:2015-10-25 19:25:10

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

以下问题出现在竞赛中(现在已经结束了) 比赛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,我认为我们必须在n,m时间内为给定O(n)解决此问题[可能需要对此进行优化]一个也。请帮我解决这个问题。 我的解决方案使用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;
}

1 个答案:

答案 0 :(得分:0)

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

以下Javascript中的代码示例解决了0.026ms中:set paste的示例,以及i5桌面上2.8ms n,m = 200,3的最差情况;我不知道比赛的时间限制是什么,但是10000个随机案例大约需要3秒钟。而C ++实现当然要快得多。

n,m = 10000,2