繁体   English   中英

C ++代码执行速度显着下降

[英]Significant C++ code execution slowdown

因此,我必须解决一个USACO问题,涉及计算所有<= 100M的素数并打印其中的所有素数,这些素数是回文数,而限制是16MB内存和1秒执行时间。 因此,我不得不进行很多优化。 请看下面的代码块:

for(int i = 0; i < all.size(); ++i)
    {
        if(all[i] < a) continue;
        else if(all[i] > b) break;
        if(isPrime(all[i]))
        {
            char buffer[50];
            //toString(all[i], buffer);
            int c = all[i];
            log10(2);
            buffer[3] = 2;
            //buffer[(int)log10(all[i])+1] = '\n';
            //buffer[(int)log10(all[i])+2] = '\0';
            //fputs(buffer, pFile);
        }
    }

现在,它在令人满意的0.5秒范围内执行,但是当我将log10(2)更改为log10(all[i])它飞涨了将近2秒! 没有明显的原因。 我将all [i]分配给变量c,它根本不会减慢执行速度,但是当我将all [i]作为参数传递时,它会使代码慢4倍! 有什么想法为什么会发生以及如何解决?

整个代码:

/*
ID: xxxxxxxx
PROG: pprime
LANG: C++11
*/
#include <fstream>
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <string>
#include <cstring>
#include <algorithm>
#include <list>
#include <ctime>
#include <cstdio>
using namespace std;

typedef struct number Number;
ifstream fin("pprime.in");
ofstream fout("pprime.out");
int MAXN = 100000000;
unsigned short bits[2000000] = {};
vector<int> primes;
vector<int> all;
int a, b;
short getBit(int atPos)
{
    int whichNumber = (atPos-1) / 16;
    int atWhichPosInTheNumber = (atPos-1) % 16;
    return ((bits[whichNumber] & (1 << atWhichPosInTheNumber)) >> atWhichPosInTheNumber);
}

void setBit(int atPos)
{
    int whichNumber = (atPos-1) / 16;
    int atWhichPosInTheNumber = (atPos-1) % 16;
    int old = bits[whichNumber];
    bits[whichNumber] = bits[whichNumber] | (1 << atWhichPosInTheNumber);
}

void calcSieve()
{
    for(int i = 2; i < MAXN; ++i)
    {
        if(getBit(i) == 0)
        {
            for(int j = 2*i; j <= (MAXN); j += i)
            {
                setBit(j);
            }
            primes.push_back(i);
        }
    }
}
int toInt(list<short> integer)
{
    int number = 0;
    while(!integer.empty())
    {
        int current = integer.front();
        integer.pop_front();
        number = number * 10 + current;
    }
    return number;
}
void toString(int number, char buffer[])
{
    int i = 0;
    while(number != 0)
    {
        buffer[i] = number % 10 + '0';
        number /= 10;
    }
}
void DFS(list<short> integer, int N, int atLeast)
{
    if(integer.size() > N)
    {
        return;
    }
    if(!(integer.size() > 0 && (integer.front() == 0 || integer.back() % 2 == 0)) && atLeast <= integer.size())
    {
        int toI = toInt(integer);
        if(toI <= b) all.push_back(toInt(integer));
    }

    for(short i = 0; i <= 9; ++i)
    {
        integer.push_back(i);
        integer.push_front(i);
        DFS(integer, N, atLeast);
        integer.pop_back();
        integer.pop_front();
    }
}
bool isPrime(int number)
{
    for(int i = 0; i < primes.size() && number > primes[i]; ++i)
    {
        if(number % primes[i] == 0) return false;
    }
    return true;
}
int main()
{
    int t = clock();
    ios::sync_with_stdio(false);
    fin >> a >> b;
    MAXN = min(MAXN, b);
    int N = (int)log10(b) + 1;
    int atLeast = (int)log10(a) + 1;
    for(short i = 0; i <= 9; ++i)
    {
        list<short> current;
        current.push_back(i);
        DFS(current, N, atLeast);
    }
    list<short> empty;
    DFS(empty, N, atLeast);
    sort(all.begin(), all.end());
    //calcSieve
    calcSieve();
    //


    string output = "";
    int ends =  clock() - t;
    cout<<"Exexution time: "<<((float)ends)/CLOCKS_PER_SEC<<" seconds";
    cout<<"\nsize: "<<all.size()<<endl;
    FILE* pFile;
    pFile = fopen("pprime.out", "w");


    for(int i = 0; i < all.size(); ++i)
    {
        if(all[i] < a) continue;
        else if(all[i] > b) break;
        if(isPrime(all[i]))
        {
            char buffer[50];
            //toString(all[i], buffer);
            int c = all[i];
            log10(c);
            buffer[3] = 2;
            //buffer[(int)log10(all[i])+1] = '\n';
            //buffer[(int)log10(all[i])+2] = '\0';
            //fputs(buffer, pFile);
        }
    }

    ends =  clock() - t;
    cout<<"\nExexution time: "<<((float)ends)/CLOCKS_PER_SEC<<" seconds";
    ends =  clock() - t;
    cout<<"\nExexution time: "<<((float)ends)/CLOCKS_PER_SEC<<" seconds";
    fclose(pFile);
    //fout<<output;

    return 0;
}

我认为您已经倒退了。 生成所有可能的回文集(如果DFS实际上正在执行此功能……使我感到困惑),然后检查其中哪些是素数似乎很奇怪。 特别是因为无论如何您都必须生成素数。

另一件事是,你正在做一个线性搜索isPrime ,这是不考虑的事实数组进行排序的优势。 请改用二进制搜索。

而且,对DFS函数使用list而不是vector会损害您的运行时。 尝试使用deque

现在,所有这些都说明了,我认为您应该以其他方式进行此操作。 有很多回文不是最主要的回文。 生成它们有什么意义? 您只需检查一个简单的堆栈即可检查数字是否是回文。 像这样:

bool IsPalindrome( unsigned int val )
{
    int digits[10];
    int multiplier = 1;
    int *d = digits;

    // Add half of number's digits to a stack
    while( multiplier < val ) {
        *d++ = val % 10;
        val /= 10;
        multiplier *= 10;
    }

    // Adjust for odd-length palindrome
    if( val * 10 < multiplier ) --d;

    // Check remaining digits
    while( val != 0 ) {
        if(*(--d) != val % 10) return false;
        val /= 10;
    }

    return true;
}

这完全避免了调用log10的需要,并且消除了所有回文产生。 筛子非常快,之后您只需测试几千个素数,其中大部分不会是回文。

现在,您的整个程序将变成这样:

calcSieve();
for( vector<int>::iterator it = primes.begin(); it != primes.end(); it++ ) {
    if( IsPalindrome(*it) ) cout << *it << "\n";
}

需要指出的另一件事。 实际上有两件事:

int MAXN = 100000000;
unsigned short bits[2000000] = {};
  1. bits太短,无法代表1亿个标志。
  2. bits未初始化。

要解决这两个问题,请尝试:

unsigned short bits[1 + MAXN / 16] = { 0 };

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM