【问题标题】:Painfully slow maze making program痛苦缓慢的迷宫制作程序
【发布时间】:2014-04-05 19:51:21
【问题描述】:

我正在编写一个程序,可以生成你想要的任何大小的迷宫。它通过首先创建迷宫中的每个单元并假设它们完全被围住来做到这一点。它们每个都被声明为自己的集合。然后随机选择一个单元格,然后随机选择一个方向来打破墙壁。随机方向函数确保它也是该单元格的有效方向。该程序确保它希望加入的两个单元格没有以某种方式连接,如果它们没有连接,它会打破墙壁。如果它们已经直接或间接连接,那么它会选择一个新的随机单元格和方向。这种情况一直持续到剩下的组数仅为 1,以确保您可以从迷宫中的任何点到达任何其他点。该程序有效,但速度非常慢。我不认为它应该像现在这样慢,我不确定为什么。

我可以想象一个场景,所有单元都连接在一起,但只有一个。因此,随机选择一个单元格需要一些时间,这可能会减慢速度,但我想当你处理不到 100,000 个单元格时,它仍然不应该花这么长时间。兰德在吐出数字方面应该很快。

我在下面附上了我的代码。它相当简单,但我很抱歉缺少注释。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>

using namespace std;

class dset {
    struct element {
        element() { rank=0, parent=-1; }
        int rank;
        int parent;
        vector<int> connections;
    };

    public:
        dset(int nr=0,int nc=0);

        int size() {return Nsets; }

        int merge (int, int);
        int find(int);

        // Functions
        bool isin(int i, vector<int> test);
        int randdir(int i);
        int randcell();
        int dir(int, int);
        void print();
        vector<int> possibledir(int cell);
        vector<int> walls(int cell, vector<int> possible);
    private:
        int Nsets;
        int nrows, ncols;
        vector<element> S;
};

int main(int argc, char* argv[]){

    int nrows, ncols, cell, direction;

    if (argc != 3){
        cout << "Usage: nrows ncols\n";
    }

    stringstream convert;


    convert << argv[1];
    convert << " ";
    convert << argv[2];
    convert >> ncols;
    convert >> nrows;


    dset maze(nrows,ncols);
    srand(time(NULL));


    while(maze.size() != 1){

        cell = maze.randcell();
//      cell = 11; 
        direction = maze.randdir(cell);
//      direction = 0;
//      cout << "cell: " << cell << "  direction: " << direction << "  new cell: " << maze.dir(cell, direction) <<endl << endl;
//      cout << maze.size() << endl<<endl;;
        maze.merge(cell, maze.dir(cell, direction));
    }

    maze.print();

}

dset::dset(int nr,int nc) {
    nrows = nr;
    ncols = nc;

    int N = (nrows * ncols);
    if (0<N) S.insert(S.end(), N, element());
    Nsets = N;
}
void dset::print(){
    vector<int> wall;
    cout << "MAZE " << nrows << " " << ncols << endl;
    for ( int i = 0; i < (nrows*ncols); i++ ){

        wall = walls(i,possibledir(i));

        for( int j = 0; j < wall.size(); j++){
            if (i < wall[j])
                cout << i << " " << wall[j] << endl;

    }
}
}



int dset::randcell(){
    return (rand()%(nrows*ncols));
}

int dset::dir(int cell, int direction){
    if(direction == 0)
        return (cell - 1);
    if(direction == 1)
        return (cell - (ncols));
    if(direction == 2)
        return (cell+1);
    if(direction == 3)
        return (cell + ncols);

}


int dset::randdir(int i){

    srand(time(NULL));
    int direction;
    vector<int> used;
//cout << "i : " << i << endl;  
    while (true){
        direction = rand() % 4;
        while (true){
            if(isin(direction,used))
                direction = rand()%4;
            else
                break;
        }
        //      cout << "rand: " << direction << endl;

        if(direction ==0){
            if( i != 0){
//              cout << 0 << " i%(ncols -1) :" << (i%(ncols -1)) << endl; 
                if(i%(ncols) != 0){
                    break;
                }

            }

        }

        if(direction == 1){
//              cout << 1 << " i - ncols :" << (i-ncols) << endl; 
            if(i-ncols > 0){
                break;
            }


        }

        if (direction == 2){
//              cout << 2 << " i%(ncols) :" << (i%ncols) << endl; 
            if ( i == 0 )
                break;
            if (i%ncols != ncols-1){
                break;
            }

        }

        if (direction == 3){
            if (i+ncols < ((nrows*ncols))){
//              cout << 3 << " i+ncols :" << (i+ncols) << endl; 
                break;
            }

        }

        used.push_back(direction);
    }

    return direction;
}

vector<int> dset::possibledir(int cell){

    vector<int> possible;
//  cout << "cell  " << cell << " possible connections:\n";
    for (int i = 0; i < 4; i++){

        if (i == 0){
            if( cell != 0 ){
                if(cell%(ncols) !=0){
//                  cout << dir(cell,i) <<endl;
                    possible.push_back(dir(cell,i));
                }
            }
        }

        if(i==1){
            if (cell-ncols > 0){
//              cout<<dir(cell,i) <<endl;
                possible.push_back(dir(cell,i));
            }
        }

        if(i==2){
            if(cell == 0){
//              cout<<dir(cell,i) <<endl;
                possible.push_back(1);
            }else if(cell%ncols != ncols-1){
//              cout<<dir(cell,i) <<endl;
                possible.push_back(dir(cell,i));
            }

        }

        if(i==3){
            if ( cell+ncols < ((nrows*ncols))){
//              cout<<dir(cell,i) <<endl;
                possible.push_back(dir(cell,i));
        }
        }



    }
//  cout << endl;

    return possible;
}


vector<int> dset::walls(int cell, vector<int> possible){
    vector<int> walls;

//  cout << cell <<  " connection 0: " << S[cell].connections[0] << endl;
    for(int i = 0; i < possible.size(); i++){
        if (!isin(possible[i], S[cell].connections)){
//          cout << "true\n";
            walls.push_back(possible[i]);
        }
//      cout << "false\n";
    }

    return walls;
}


int dset::merge(int i, int j) {
    int cell1 = i;
    int cell2 = j;
    i = find(i);
    j = find(j);

    if (i != j) {
        element &Si = S[i];
        element &Sj = S[j];

        // Adjust Adjacency List
//      cout << "inconnections\n";      
        S[cell1].connections.push_back(cell2);
        S[cell2].connections.push_back(cell1);
//      cout << "notinconnections\n"; 

        // merge (union) by rank
        if (Si.rank > Sj.rank)  Sj.parent = i;
        else if (Si.rank < Sj.rank) Si.parent = j;
        else { Sj.parent = i; Si.rank +=1; }

        Nsets -=1;
    }

    return find(i);

}

int dset::find(int i) {

    if (S[i].parent == -1){
        return i;
    }

    // recursive path compression
    S[i].parent = find(S[i].parent);
    return S[i].parent;

}

bool dset::isin(int i, vector<int> test){

    bool out = false;

    for(int j = 0; j < test.size(); j++){
        if(test[j] == i)
            out = true;
    }

    return out;

}

【问题讨论】:

    标签: c++ performance random maze


    【解决方案1】:

    请学会通过引用而不是值传递。

    例如:

    bool dset::isin(int i, vector<int> test)
    

    您正在按值传递向量。这意味着在调用函数时会制作完整的副本。如果您的向量有 100,000 个项目,则会制作不必要的副本。改为:

    bool dset::isin(int i, vector<int>& test)
    

    现在没有复制完成。在所有其他功能中进行相同的更改。

    您还可以按值返回一个向量,但除非证明您的编译器不能或不会优化副本,否则我会不理会这些。

    另外,请确保您正在为发布、优化的程序而不是“调试”或未优化的程序计时。由于您没有提及您正在使用的编译器,因此请在构建程序时使用生成优化代码的设置。

    【讨论】:

      【解决方案2】:

      虽然我对 c++ 了解不多,但在我看来,从您一开始的程序描述来看,当您的程序确定两个预期可连接的单元是否已经连接时,您的速度可能会变慢。由于完成此操作的大多数情况(如果不是所有情况)都必须确定单元未连接,因此只有一个正确的解决方案,因此每次完成时,您的程序都必须检查/解决整个迷宫到该点以确保它已经无法连接。这意味着随着迷宫现有部分变大,完成这项任务所需的时间会越来越长。

      要测试是否是这种情况,您可以让您的程序记录每次(或 10 次)确定两个单元是否连接所需的时间,以及列表上的时间是否线性变长,那么这个或类似的东西是问题的一部分。

      您可以通过允许已连接的其他路径连接或通过简化程序检查连接的单元的方式来解决此问题。

      抱歉,我无法提供更好的针对代码的建议,但我正在研究如何创建迷宫并遇到了您的问题,希望我的回答至少值得深思。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-05
        • 1970-01-01
        • 2011-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多