[英]Total number of ways to write a positive integer as the sum of powers of 2 in efficient time
我一直在研究將n寫為2的冪的總和的方法數量並且它工作正常,但我想知道如何提高該算法的運行時效率。 它無法在任何合理的時間內(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;
}
由於我們處理某些基礎的權力(在這種情況下為2),我們可以在O(n)
時間(和空間,如果我們考慮固定大小的計數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 <= l
的因子。
將它們以正確的順序(降序)相乘,在每個步驟中都知道只有索引可被b^i
整除的系數是非零的,因此僅需要n/b^k + n/b^(k-1) + ... + n/b + n
系數的加法,總O(n)
。
代碼(不防止更大的參數溢出):
#include <stdio.h>
unsigned long long partitionCount(unsigned n);
int main(void) {
unsigned m;
while(scanf("%u", &m) == 1) {
printf("%llu\n", partitionCount(m));
}
return 0;
}
unsigned long long partitionCount(unsigned n) {
if (n < 2) return 1;
unsigned h = n /2, k = 1;
// find largest power of two not exceeding n
while(k <= h) k <<= 1;
// coefficient array
unsigned long long arr[n+1];
arr[0] = 1;
for(unsigned i = 1; i <= n; ++i) {
arr[i] = 0;
}
while(k) {
for(unsigned i = k; i <= n; i += k) {
arr[i] += arr[i-k];
}
k /= 2;
}
return arr[n];
}
工作得足夠快:
$ echo "1000 end" | time ./a.out
1981471878
0.00user 0.00system 0:00.00elapsed
這種問題的一般適用方法是緩存中間結果,例如如下:
#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
*/
原始程序(我稱之為nAsSum0
)的結果是:
$ 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
...都在Cygwin下的Windows 7 PC上運行。 因此,具有緩存的版本太快,無法准確測量time
,而原始版本需要大約1分鍾才能運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.