我已经编写了一个简单的Haskell程序来解决难题。该算法是正确的,它为n = 40
产生了正确的结果,即14466.然而,对于n = 100
,程序变得非常慢,以至于我甚至没有耐心等待它。
我不明白它为什么这么慢,因为我希望它能缓存中间函数调用的所有结果,你知道,Haskell是一种懒惰的语言而且都是。
我的编译器是GHCi 7.6.3。
我尝试过分析,但这只是告诉我99.9%的时间花在isLoosing函数上。
isLoosing :: Int -> Int -> Bool
isLoosing x y
| y < x = isLoosing y x
| x == 0 = True
| x == 1 = False
| y `mod` x == 0 = False
| otherwise = and [ not (isLoosing (y-x*m) x) |
m <- [1..(y `div` x)] ]
loosingSum :: Int -> Int
loosingSum n = sum [ x + y |
x <- [1..(n-1)],
y <- [(x+1)..n],
isLoosing x y == True ]
main = print $ loosingSum 40
答案 0 :(得分:0)
我发现需要使用memoization来加快速度。我为我找到了一个很好的库,如下所示。此代码现在运行0.12秒,但不幸的是,这仍然太慢。使用n = 10000
运行它再次花费了相当长的时间,而使用C ++中的可比算法则需要几秒钟。所以我开始认为Haskell可能不是解决所有问题的方法......
import Data.MemoCombinators (memo2,integral)
bigN :: Int
bigN = 100
isLoosingCached = memo2 integral integral isLoosing
isLoosing :: Int -> Int -> Bool
isLoosing x y
| y < x = isLoosingCached y x
| x == 0 = True
| x == 1 = False
| y `mod` x == 0 = False
| otherwise = and [ not (isLoosingCached (y-x*m) x) |
m <- [1..(y `div` x)] ]
loosingSum :: Int
loosingSum = sum [ x + y |
x <- [1..(n-1)],
y <- [(x+1)..n],
isLoosingCached x y == True ]
where n = bigN
main = print $ loosingSum
这个解决方案是C ++就是这样。最大的区别是它使用迭代而不是递归。
#include <iostream>
#include <stdint.h>
#define N 10000
short STATES[N + 1][N + 1];
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
uint64_t sum = 0;
for (int y = 0; y <= N; y++)
{
STATES[0][y] = 1;
STATES[1][y] = -1;
}
for (int x = 2; x < N; x++)
for (int y = x; y <= N; y += x)
STATES[x][y] = -1;
for (int x = 2; x < N; x++)
{
for (int y = x + 1; y <= N; y++)
{
if (STATES[x][y] == 0)
{
int k;
for (int y_ = y - x; y_ > 0; y_ -= x)
{
if (y_ > x)
k = STATES[x][y_] * -1;
else
k = STATES[y_][x] * -1;
if (k == -1)
break;
}
STATES[x][y] = k;
}
if (STATES[x][y] == 1)
sum += x + y;
}
cout << sum << endl;
system("pause");
}
}