n-ферзей без трех ферзей на одной линии

Я пытаюсь сгенерировать экземпляры n-ферзей с более сильным условием, чтобы никакие 3 ферзя не находились на одной линии.

То есть, если (r0, c0), (r1, c1), (r2, c2) — три уникальные позиции ферзей,

затем (c0 - c1) * (r0 - r2) != (c0 - c2) * (r0 - r1).


Прямо сейчас я пытаюсь использовать простое стохастическое восхождение на холм, чтобы поменять местами две строки в каждой итерации, чтобы уменьшить количество конфликтов. Используя это, я могу решить до n ~ 200.

#include <cstdio>
#include <cstdlib>
#include <ctime>

class Board{
public:
    int size;
    int * ar;
    Board(int size): size(size){
        ar = new int[size];
        for(int i=0;i<size;i++){
            ar[i] = i+1;
        }
        for(int i=0;i<size*50;i++){
            cell_swap(rand() % size, i % size);
        }
    }

    void cell_swap(int a, int b){
        if(a == b) return;
        ar[a] ^= ar[b];
        ar[b] ^= ar[a];
        ar[a] ^= ar[b];
    }

    int clash_count(int i){
        int count = 0;
        for(int j=0;j<size;j++){
            if(i==j) continue;
            for(int k=j+1;k<size;k++){
                if(i==k) continue;
                if((i-k)*(ar[i]-ar[j]) == (i-j)*(ar[i]-ar[k])){
                    count++;
                }
            }
        }
        return count;
    }

    void print(){
        for(int i=0;i<size;i++){
            printf("%4d", ar[i]);
        }
        printf("\n");
    }

    ~Board(){
        delete[] ar;
    }
};

int main(int argc, char *argv[]){
    srand(time(NULL));
    int size = argc > 1 ? atoi(argv[1]) : 10;
    Board * b = new Board(size);
    bool flag = 0;
    while(1){
        // b->print();
        int clashes[size];
        int total_clash = 0;
        for(int i=0;i<size;i++){
            clashes[i] = b->clash_count(i);
            total_clash += clashes[i];
        }
        total_clash /= 3;
        printf("clash: %d\n", total_clash);
        if(total_clash == 0) break;
        int moves[(size*(size-1))<<1][3];
        int ix = 0;
        int s = 0;
        for(int i=0;i<size;i++){
            for(int j=0;j<size;j++){
                b->cell_swap(i, j);
                moves[ix][0] = clashes[i] + clashes[j];
                moves[ix][0] -= b->clash_count(i);
                moves[ix][0] -= b->clash_count(j);
                if(moves[ix][0] > 0){
                    s += moves[ix][0];
                    moves[ix][1] = i;
                    moves[ix][2] = j;
                    ix++;
                }
                b->cell_swap(i, j);
            }
        }
        if(s == 0) continue;
        int rand_ = rand() % s;
        int s_ = 0;

        for(int i=0;i<ix;i++){
            if(moves[i][0] < 0) continue;
            s_ += moves[i][0];
            if(s_ > rand_){
                b->cell_swap(moves[i][1], moves[i][2]);
                break;
            }
        }
    }
    b->print();
    return 0;
}

Я хочу масштабировать свой алгоритм. Я хочу сократить время работы, чтобы найти конфликты. В любом случае, чтобы улучшить сложность в каждой итерации?


person rnbguy    schedule 12.10.2016    source источник
comment
Вот программа для задачи с n ферзями. codereview.stackexchange.com/questions/77669/   -  person hamster on wheels    schedule 12.10.2016
comment
более быстрый: stackoverflow.com/questions/27697929/   -  person hamster on wheels    schedule 12.10.2016
comment
Благодарю. Я начну с более быстрого и попытаюсь добавить новое ограничение и посмотреть, работает ли оно.   -  person rnbguy    schedule 12.10.2016