Улучшение временной сложности шахматной доски - PullRequest
2 голосов
/ 17 июня 2019

Я написал программу для печати шахматной доски. Это выглядит так: (комментарии объясняют логику и переменные)

#include<iostream>
#include<vector>
#include<string>
#include<fstream>
#include<cstdlib>
using namespace std;
int block_size = 8; //block_size * block_size is the size of each block on the board
int dim = 8; //8 blocks on every row or column, each block containing block_size * block_size pixels
int res = dim * block_size; //total number of pixels is res * res (resolution)

int main(){
    int size = 8;
    vector<vector<int> > vec(res);  

    for (int i = 0; i < res; i++) { 

        vec[i] = vector<int>(res); 
        for (int j = 0; j < res; j++) {
            vec[i][j] = 0; 
        }
    }//initialize all pixels to 0
    //int count=0;
    /*
    allocate black or white pixels based on odd/even status of array indices which are picked
    based on multiples of block_size
    ex. i,j = 0,4,8,16...
    pixels are allocated from the starting point of a particular coordinate like so: two for loops for i,j + d 
    where 0<=d<block_size
    */
    for (int i = 0; i < res; i=i+block_size) { 
        for (int j = 0; j < res; j=j+block_size) {
            //cout<<count<<" ";
            //count++;
            //cout<<i/block_size;
            if (int ((i/block_size)%2 == 0)){
                if(int ((j/block_size)%2 == 0)){
                    for(int k=i;k<i+block_size;k++){
                        for (int l=j;l<j+block_size;l++){
                            vec[k][l]=0;
                        }
                    }
                }
                else{
                    for(int k=i;k<i+block_size;k++){
                        for (int l=j;l<j+block_size;l++){
                            vec[k][l]=255;
                        }
                    }
                }

                }
                else{
                    if(int ((j/block_size)%2 == 0)){
                    for(int k=i;k<i+block_size;k++){
                        for (int l=j;l<j+block_size;l++){
                            vec[k][l]=255;
                        }
                    }
                }
                else{
                    for(int k=i;k<i+block_size;k++){
                        for (int l=j;l<j+block_size;l++){
                            vec[k][l]=0;
                        }
                    }
                }

                }

            }
        }

    cout<<endl;
    /*
    for (int i = 0; i < size; i++) { 
        for (int j = 0; j < vec[i].size(); j++) 
            cout << vec[i][j] << " "; 
        cout << endl; 
    }
    */
    string filename = "chessboard.pgm";
    ofstream pgmFile(filename);


    pgmFile << "P2" << endl;
    pgmFile << res << " " << res << endl;
    pgmFile << 255 << endl;


    for(int i=0;i<res;i++){
        for(int j=0;j<res;j++){
            pgmFile << vec[i][j] << " ";
        }
        pgmFile << endl;
    }

    pgmFile.close();
    return 0;
}

Выходные данные программы вводятся в изображение pgm, которое затем записывается в файл для просмотра (Irfanview может использоваться для просмотра изображения pgm).
Алгоритм выглядит так:
- выделить черные или белые пиксели на основе нечетного / четного статуса индексов массива, которые выбраны
на основе кратных block_size
ех. i, j = 0,4,8,16 ...
- пиксели выделяются из начальной точки конкретной координаты: 2 для циклов для i, j + d, где d находится в диапазоне от 0 до block_size, не включая block_size
Прямо сейчас, похоже, сложность O (n ^ 4). Любые идеи о том, какие шаги я могу предпринять, чтобы уменьшить сложность?

Ответы [ 3 ]

1 голос
/ 17 июня 2019

Ваша временная сложность уже оптимальна. Конечно, вы делаете несколько проходов по входу, но эта константа игнорируется, и сложность сводится к числу пикселей в изображении (или O (side_length 2 * block_size 2 ) или O (res 2 ) или просто O (n), если n - размер изображения).

Сказав это, есть много повторяющегося кода, и вы можете полностью исключить векторы, что делает вашу пространственную сложность постоянной.

Вот переписать, сохранив только самое необходимое:

#include <cstdlib>
#include <fstream>

int main() {
    int block_size = 8;
    int dim = 8;
    int res = dim * block_size;
    std::ofstream pgm("chessboard.pgm");
    pgm << "P2\n" << res << " " << res << "\n255\n";

    for (int i = 0; i < res; i++) {
        for (int j = 0; j < res; j++) {
            pgm << ((j / block_size + i / block_size) % 2 ? 255 : 0) << " ";
        }

        pgm << "\n";
    }

    pgm.close();
    return 0;
}

Наконец: у шахмат обычно есть черный квадрат в левом нижнем углу, так что вы можете подумать о том, чтобы поменять цвета.

1 голос
/ 17 июня 2019

Шахматная доска имеет хороший рисунок. Он чередует четные строки (начиная с черного квадрата) и нечетные строки (начиная с белого). Это предполагает естественную структуру программы:

    for (row_pair = 0; row_pair < dim / 2; row_pair++) {
        emit_row(something_even);
        emit_row(something_odd);
    }

В свою очередь, каждая строка состоит из block одинаковых тонких (один пиксель в высоту) линий. Подготовьте их для четных и нечетных рядов; только два.

    line_t even_line = prepare_even_line(block_size);
    line_t odd_line = prepare_odd_line(block_size);

и используйте как в

    void emit_row(line_t& line) {
        for (int i = 0; i < block_size; i++) {
            emit_line(line);
        }
    }

Теперь вы можете

    for (row_pair = 0; row_pair < dim / 2; row_pair++) {
        emit_row(even_line);
        emit_row(odd_line);
    }

Осталось только выяснить, каким должен быть line_t и как подготовить тонкую линию. emit должно быть самоочевидным.

1 голос
/ 17 июня 2019

Вы можете использовать что-то вроде этого (это полный код для подачи доски в консоль).

Каждый пиксель посещается один раз, как в вашей реализации, сложность тоже O(res^2), но выглядит проще.

Для block_size -с, равных степеням 2, rx и ry могут быть вычислены с помощью побитовых операций

int main()
{
    int block_size = 4; //block_size * block_size is the size of each block on the board
    int dim = 4; //8 blocks on every row or column, each block containing block_size * block_size pixels
    int res = dim * block_size; //total number of pixels is res * res (resolution)
    vector<vector<int> > vec(res);

    for (int i = 0; i < res; i++) {
        vec[i] = vector<int>(res);
        }

    for (int y = 0; y < res; y++) {
        int ry = ((y % (block_size * 2)) < block_size) ? 0 : 1;
        for (int x = 0; x < res; x++) {
            int rx = ((x % (block_size * 2)) < block_size) ? 0 : 1;
            vec[y][x] = 255 * (ry ^ rx);
            cout << vec[y][x] << "\t";
        }
        cout << "\n";
    }
}

Более простой подход, предложенный Jarod42:

for (int y = 0; y < res; y++) {
    for (int x = 0; x < res; x++) {
        vec[y][x] = ((y / block_size) + (x / block_size)) % 2 == 0 ? 0 : 255;

результат для 4x4:

0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
0       0       0       0       255     255     255     255     0       0       0       0       255     255     255     255
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
255     255     255     255     0       0       0       0       255     255     255     255     0       0       0       0
...