C++ 在有效时间内将正整数写入为2的幂和的方法总数

C++ 在有效时间内将正整数写入为2的幂和的方法总数,c++,c,algorithm,performance,runtime,C++,C,Algorithm,Performance,Runtime,我一直在看,它工作得很好,但我想知道如何提高该算法的运行时效率。它无法在任何合理的时间内(10秒以下)计算任何高于~1000的数据 我假设它与分解成子问题有关,但不知道如何进行。我在想O(n)或O(nlogn)运行时之类的东西——我相信这是可能的。我只是不知道如何有效地分配工作 通过Chasefornone编码 #include<iostream> using namespace std; int log2(int n) { int ret = 0; while

我一直在看,它工作得很好,但我想知道如何提高该算法的运行时效率。它无法在任何合理的时间内(10秒以下)计算任何高于~1000的数据

我假设它与分解成子问题有关,但不知道如何进行。我在想O(n)或O(nlogn)运行时之类的东西——我相信这是可能的。我只是不知道如何有效地分配工作

通过Chasefornone编码

 #include<iostream>
using namespace std;

int log2(int n)
{
    int ret = 0;
    while (n>>=1) 
    {
        ++ret;      
    }
    return ret;
}

int power(int x,int y)
{
    int ret=1,i=0;
    while(i<y)
    {
        ret*=x;
        i++;
    }
    return ret;
}

int getcount(int m,int k)
{
    if(m==0)return 1;
    if(k<0)return 0;
    if(k==0)return 1;
    if(m>=power(2,k))return getcount(m-power(2,k),k)+getcount(m,k-1);
    else return getcount(m,k-1);

}

int main()
{
    int m=0;
    while(cin>>m)
    {
        int k=log2(m);
        cout<<getcount(m,k)<<endl;
    }
    return 0;
}
#包括
使用名称空间std;
int log2(int n)
{
int-ret=0;
而(n>>=1)
{
++ret;
}
返回ret;
}
整数幂(整数x,整数y)
{
int-ret=1,i=0;
while(i>m)
{
int k=log2(m);

因为我们在处理某个基的幂(在这种情况下是2),所以我们可以在<代码> O(n)< /代码>时间(和空间,如果我们考虑固定大小的计数)时很容易做到这一点。 关键是分区的生成函数。设
p(n)
为写入
n
的方法数,作为基
b
的幂和

然后考虑

        ∞
f(X) =  ∑  p(n)*X^n
       n=0
人们可以把
f
写成无限乘积

        ∞
f(X) =  ∏  1/(1 - X^(b^k))
       k=0

如果只希望系数达到某个极限<代码> L>代码>,只需要考虑<代码> b^ k的一个因素,一个普遍适用的方法是这样的问题,即缓存中间结果,例如:

#include <iostream>
#include <map>

using namespace std;

map<pair<int,int>,int> cache;

/* 
The log2() and power() functions remain unchanged and so are omitted for brevity
 */
int getcount(int m,int k)
{
    map<pair<int,int>, int>::const_iterator it = cache.find(make_pair(m,k));
    if (it != cache.end()) {
        return it->second;
    }
    int count = -1;
    if(m==0) {
       count = 1;
    } else if (k<0) {
        count = 0;
    } else if (k==0) {
       count = 1;
    } else if(m>=power(2,k)) {
        count = getcount(m-power(2,k),k)+getcount(m,k-1);
    } else {
        count = getcount(m,k-1);
    }
    cache[make_pair(m,k)] = count;
    return count;
}

/* 
The main() function remains unchanged and so is omitted for brevity
 */
对于具有缓存的版本:

$ echo 1000 | time ./nAsSum
1981471878
0.01user 0.01system 0:00.09elapsed 32%CPU (0avgtext+0avgdata 466176maxresident)k
0inputs+0outputs (1873major+0minor)pagefaults 0swaps

…都在Cygwin下的Windows 7 PC上运行。因此,带缓存的版本速度太快,无法准确测量
时间
,而原始版本运行大约需要1分钟。

请向我们展示您的代码…如果您最多可以一次使用两次幂,答案是常量:一。否则,它就足以解决问题仅用于二次幂。编辑以添加代码-来自Chasefornone-不是我自己的。太好了!谢谢。我仍然习惯于二进制和有符号/无符号数字的所有数学。如何防止大输入溢出?分成两部分并运行两次?不,第一次溢出将在结果中发生,您需要使用任意然后是精度类型。然后下一种可能是索引中溢出(
i
)为此,使用
unsigned long long
会让您走得更远,在出现溢出危险之前,您的内存早就用完了。此外,如果您想处理大于几千的输入,最好
calloc
数组,而不是在堆栈上放置VLA。
#include <iostream>
#include <map>

using namespace std;

map<pair<int,int>,int> cache;

/* 
The log2() and power() functions remain unchanged and so are omitted for brevity
 */
int getcount(int m,int k)
{
    map<pair<int,int>, int>::const_iterator it = cache.find(make_pair(m,k));
    if (it != cache.end()) {
        return it->second;
    }
    int count = -1;
    if(m==0) {
       count = 1;
    } else if (k<0) {
        count = 0;
    } else if (k==0) {
       count = 1;
    } else if(m>=power(2,k)) {
        count = getcount(m-power(2,k),k)+getcount(m,k-1);
    } else {
        count = getcount(m,k-1);
    }
    cache[make_pair(m,k)] = count;
    return count;
}

/* 
The main() function remains unchanged and so is omitted for brevity
 */
$ echo 1000 | time ./nAsSum0
1981471878
59.40user 0.00system 0:59.48elapsed 99%CPU (0avgtext+0avgdata 467200maxresident)k
0inputs+0outputs (1935major+0minor)pagefaults 0swaps
$ echo 1000 | time ./nAsSum
1981471878
0.01user 0.01system 0:00.09elapsed 32%CPU (0avgtext+0avgdata 466176maxresident)k
0inputs+0outputs (1873major+0minor)pagefaults 0swaps