Приветствую.
Возник вопрос, насчет вычисления последовательности схожей с последовательностью чисел Фибоначчи, только в которой каждый член равен сумме трех предыдущих. Последовательность начинается с трех единиц: 1, 1, 1, 3, 5, 9, .... Я хочу находить число этой последовательности по номеру. Номер лежит в пределах от 1 до 10000.
Я изучил последовательность Фибоначчи и нашел несколько формул для вычисления n-ого члена, в частности, формулу Бине(через золотое сечение), и другие. Но я не знаю, как их применить к моей последовательности.
Вопрос: как получить формулу для вычисления n-ого члена последовательности без нахождения всех предыдущих членов? Очевидно, что рекурсивный подход для n=10000 не подходит.
UPD: время выполнения программы для любых n не должно превышать 1 секунду.
Ответ
Данный рекурсивный алгоритм нужно переписать итеративно. В этом случае сложность стает O(n), а памяти нужно будет константно (ну почти - числа то увеличиваются).
Вот пример, как посчитать и вывести
#include
using namespace std;
mpz_class pp(int n) {
if (n < 1 || n >= 10000000) return 0;
if (n < 3) return 1;
mpz_class a = 1; mpz_class b = 1; mpz_class c = 1;
for (int i = 3; i < n; i++) {
mpz_class t = a + b + c;
c = b; b = a; a = t;
}
return a;
}
int main() {
auto t1 = std::chrono::steady_clock::now();
cout << pp(1000000) << endl;
auto t2 = std::chrono::steady_clock::now();
auto d_milli = std::chrono::duration_cast
Вопрос в том, насколько это быстро? Для миллионного элемента на моей машине потребовалось 22секунды. Для 100000 элемента порядка 145мс. Для 10000 элемента это 2-4 мс.
И на последок. Как это скомпилировать (на линуксе):
g++ -std=c++11 ff.cpp -lgmpxx -lgmp
P.S. нужно не забыть поставить библиотеку gmp.
upd
решил переписать с ручной реализацией сложения больших чисел. Код сложения не самый оптимальный, но gmp проигрывает всего лишь 6-8 раз. Если переписать с sse, думаю, можно будет вытянуть больше. Но даже для такой простой реализации в лоб, думаю уже не плохо.
#include
#include
#define CLEN 8
#define BASE 100000000
class bi
{
public:
bi()
{
}
bi(std::string data)
{
for (int i = 0; i < data.length(); i+= CLEN) {
int r = std::stoi(data.substr(i, CLEN));
m_digits.push_back(r);
}
}
bi(const bi& data)
{
m_digits = data.m_digits;
}
bi(int data)
{
while (data > 0) {
m_digits.push_back(data % BASE);
data = data / BASE;
}
}
bi& operator=(bi data)
{
if (this != &data) {
m_digits = data.m_digits;
}
return *this;
}
friend std::ostream& operator<< (std::ostream& stream, const bi& b);
friend bi operator+( const bi& lhs, const bi& rhs );
private:
std::vector
};
std::ostream& operator<< (std::ostream& stream, const bi& b)
{
for (int i = b.m_digits.size() - 1; i >= 0; i--) {
if (i != b.m_digits.size() - 1) {
stream << std::setfill('0') << std::setw(CLEN);
}
stream << b.m_digits[i];
}
return stream;
}
bi operator+( const bi& lhs, const bi& rhs ) {
bi result;
size_t ls = lhs.m_digits.size();
size_t rs = rhs.m_digits.size();
size_t lm = std::min(ls, rs);
result.m_digits.reserve(std::max(ls, rs) + 1);
int p = 0;
for (size_t i = 0; i < lm; i++) {
int c = lhs.m_digits[i] + rhs.m_digits[i] + p;
result.m_digits.push_back(c % BASE);
p = c / BASE;
}
if (ls > rs) {
for (size_t i = lm; i < ls; i++) {
int c = lhs.m_digits[i] + p;
result.m_digits.push_back(c % BASE);
p = c / BASE;
}
}
if (rs > ls) {
for (size_t i = lm; i < rs; i++) {
int c = rhs.m_digits[i] + p;
result.m_digits.push_back(c % BASE);
p = c / BASE;
}
}
if (p > 0) {
result.m_digits.push_back(p);
}
return result;
}
template
template
std::cout << pp
auto t2 = std::chrono::steady_clock::now();
auto d_milli = std::chrono::duration_cast
int main()
{
int n = 10000;
int gmp = test
Комментариев нет:
Отправить комментарий