图形编辑器编程挑战解决时间限制超过c ++ [关闭]

Posted

技术标签:

【中文标题】图形编辑器编程挑战解决时间限制超过c ++ [关闭]【英文标题】:Graphical editor programming challenge solution time limit exceeded c++ [closed] 【发布时间】:2016-10-29 11:05:52 【问题描述】:

以下是我对图形编辑器编程挑战的解决方案,详细here(我花了 3 天时间才解决)。虽然输出正确,但它不断产生 time_limit_exceeded 错误。我认为问题出在我实现 flood_fill 函数的方式上,当用户输入“F”作为一行的第一个字母时,该函数会被调用。如果有人解释我的代码效率低下的地方以及如何改进它,我将不胜感激。我的代码如下:

// graphical_editor.cpp : Defines the entry point for the console application.
//

    #include "stdafx.h"
    #include <iostream> //provides access to cout and cin 
    #include <string> //Always import <string> if piping std input to a string in .net 
    #include <vector>
    #include <fstream>

    using std::ofstream;
    using std::cin; 
    using std::cout; 
    using std::string;
    using std::vector;

    //This is where we store the pixels of the image
    static vector<vector <string>> image_array;
    ofstream myfile;
    //our definition of an X,Y coordinate pair. 
    typedef struct point 
        int x_coordinate, y_coordinate;
    ;

    void initialise_image();
    void clear_image(); 
    void save_image(string file_name);
    int get_image_width();
    int get_image_height();
    void color_pixel(int x, int y, string color);
    void color_point(point p, string color);
    void color_vertical_line(int x, int y1, int y2, string color);
    void color_horizontal_line(int x1, int x2, int y, string color);
    void color_box(int x1, int x2, int y1, int y2, string color);
    void flood_fill(point p, string color);
    vector<point> get_matching_neighbours(point p, string color);

    int main()
    
        string command; //first letter of a given line 
        myfile.open("example.txt");
        while (cin >> command) 
            //application terminates when command is X
            if (command.compare("X") == 0) 
                return 0;
             else if (command.compare("I") == 0) 
                initialise_image();
            
            else if (command.compare("S") == 0) 
                string file_name;
                cin >> file_name;
                save_image(file_name);
            
            else if (command.compare("L") == 0) 
                string color;
                point p;
                cin >> p.x_coordinate >> p.y_coordinate >> color;
                color_point(p, color);
            
            else if (command.compare("V") == 0) 
                string color;
                int x, y1, y2;
                cin >> x >> y1 >> y2 >> color;
                color_vertical_line(x, y1, y2, color);
            
            else if (command.compare("H") == 0) 
                string color;
                int x1, x2, y;
                cin >> x1 >> x2 >> y >> color;
                color_horizontal_line(x1, x2, y, color);
            
            else if (command.compare("K") == 0) 
                string color;
                int x1, x2, y1, y2;
                cin >> x1 >> x2 >> y1 >> y2 >> color;
                color_box(x1, x2, y1, y2, color);
            
            else if (command.compare("F") == 0) 
                string color;
                point p;
                cin >> p.x_coordinate >> p.y_coordinate >> color;
                flood_fill(p, color);
            
            else if (command.compare("C") == 0) 
                clear_image();
            
        

        return 0;
    

    void initialise_image()
    
        /*read parameters height and width*/
        int width, height; 
        cin >> width >> height;

        /*first we create a vector of vectors (numRows+1)x(numColumns matrix+1). */
        image_array.clear(); 
        for (int i = 0; i < width+ 1; i++) 
            image_array.push_back(vector<string>());
        

        /*then we initialize each element of it one by one*/
        for (int colNo = 0; colNo < width + 1; colNo++) 
            for (int rowNo = 0; rowNo < height + 1; rowNo++) 
                image_array[colNo].push_back("O");
            

        
    

    void clear_image() 
        /*we initialize each element of it one by one*/
        for (int y = 1; y < get_image_height()+1 ; y++) 
            for (int x = 1; x < get_image_width()+1; x++) 
                image_array[x][y] = "O";
            
        
    

    void save_image(string file_name) 


        myfile << file_name << "\n";
        //cout << file_name << "\n";
        for (int y = 1; y < get_image_height()+1; y++) 
            for (int x = 1; x < get_image_width()+1; x++) 
                myfile << image_array[x][y];
                //cout << image_array[x][y];
            
            myfile << "\n";
            //cout << "\n";
        
        myfile.close();
    

    int get_image_width() 
        return image_array.size()-1;

    

    int get_image_height() 
        return image_array[0].size()-1;
    

    void color_point(point p, string color) 
        color_pixel(p.x_coordinate,p.y_coordinate, color);
    

    void color_pixel(int x, int y, string color) 
        image_array[x][y] = color;
    


    void color_vertical_line(int x, int y1, int y2, string color) 
        for (int y = y1; y <= y2; y++) 
            color_pixel(x, y, color);
        
    

    void color_horizontal_line(int x1, int x2, int y, string color) 
        for (int x = x1; x <= x2; x++) 
            color_pixel(x, y, color);
        
    

    void color_box(int x1, int x2, int y1, int y2, string color) 
        for (int x = x1; x <= x2; x++) 
            for (int y = y1; y <= y2; y++) 
                color_pixel(x, y, color);
            
        
    

    string get_point_color(point p) 
        return image_array[p.x_coordinate][p.y_coordinate];
    

    void flood_fill(point p, string color) 
        vector <point> points_queue; 
        points_queue.push_back(p);
        string original_color = get_point_color(p);
        point current_point; 
        while (points_queue.size() > 0) 
            current_point = points_queue[0];

            //if the point shares a color with the original point then color it in the new color. 
            if (get_point_color(current_point).compare(original_color) == 0) 
                color_point(current_point, color);
            

            // remove current point from the queue
            points_queue.erase(points_queue.begin());

            // add it's neighbours to the queue
            vector<point> matching_neighbours = get_matching_neighbours(current_point, original_color);
            for (int i = 0; i < matching_neighbours.size(); i++) 
                points_queue.push_back(matching_neighbours[i]);
            


        


    

    bool is_valid_point(point p) 
        if (p.x_coordinate >= 1 && p.x_coordinate < get_image_width() + 1 && p.y_coordinate >= 1 && p.y_coordinate < get_image_height() + 1) 
            return true;
        
        else 
            return false; 
        
    

    vector<point> get_matching_neighbours(point p, string color) 
        vector<point> neighbours;
        point left_neighbour, right_neighbour, upper_neighbour, lower_neighbour;
        left_neighbour.x_coordinate = p.x_coordinate - 1;
        left_neighbour.y_coordinate = p.y_coordinate;
        if (is_valid_point(left_neighbour) && get_point_color(left_neighbour).compare(color) == 0) 
            neighbours.push_back(left_neighbour);
        


        right_neighbour.x_coordinate = p.x_coordinate + 1;
        right_neighbour.y_coordinate = p.y_coordinate;
        if (is_valid_point(right_neighbour) && get_point_color(right_neighbour).compare(color) == 0) 
            neighbours.push_back(right_neighbour);
        

        upper_neighbour.x_coordinate = p.x_coordinate;
        upper_neighbour.y_coordinate = p.y_coordinate + 1;
        if (is_valid_point(upper_neighbour) && get_point_color(upper_neighbour).compare(color) == 0) 
            neighbours.push_back(upper_neighbour);
        

        lower_neighbour.x_coordinate = p.x_coordinate;
        lower_neighbour.y_coordinate = p.y_coordinate - 1;

        if (is_valid_point(lower_neighbour) && get_point_color(lower_neighbour).compare(color) == 0) 
            neighbours.push_back(lower_neighbour);
        
        return neighbours;
    

【问题讨论】:

请不要在此处询问有关在线代码判断引擎的问题。任何人都不太可能从他们的测试用例中告诉你你失败的地方,因为这些通常不会被披露。即使您测试的是在本地环境中运行,您也可能错过了测试在线挑战中应用的一些边缘案例。要有创意并尝试找到它们。此外,从长远来看,这些问题可能没有任何价值,除了在在线比赛中作弊,什么都学不到。 【参考方案1】:

洪水填充存在一些非常糟糕的性能问题。

这是两个最大的:

1) 您正在使用向量作为队列。这非常慢,因为从向量的开头删除一个项目需要 O(N) 时间。改用双端队列,或者像堆栈一样使用向量而不是队列,方法是从末尾而不是开头获取项目。

2) 您将 get_matching_neighbors 返回的所有内容排入队列,但它可以返回队列中已经区域的内容。因此,您最终可能会多次扫描同一像素并将其加入队列。

要解决问题(2),您应该:

a) 如果目标像素已经是正确的颜色,则立即从泛色填充返回。那么

b) 当您将它们放入队列时,而不是当您将它们取出时,颜色像素。这样一来,您就不会对队列中已经存在的任何内容进行排队,因为队列中的任何内容都没有原始颜色。

让 get_matching_neighbors 分配一个新向量也是相当昂贵的。您应该将一个对现有向量的引用传递给它并让它替换内容,或者将它传递给队列的引用并让它重新着色并添加它找到的像素。

【讨论】:

【参考方案2】:

您可以将一些整体优化技巧应用于您的代码:

首先,规范说颜色是 1 个拉丁字符……那你为什么要使用字符串?字符串很慢,尤其是当您知道您将收到一个字符时。

第二 - 当您使用向量并且知道您将推送很多元素(并且您知道之前的数量)时,然后 reserve() 向量的实际大小以及您的元素数量'重新添加。 当您将向量附加到向量时,只需保留足够的空间,然后 insert(first.begin(), second.begin(), second.end());

更不用说我实际上建议不要使用向量......它们很容易使用,但通常比使用数组要慢。因此,如果算法本身不是很复杂 - 使用数组。还要记住,c 风格的数组比指针更快(向量对指针进行操作)。

第三 - 尽可能使用构造函数,使用预递增/递减运算符,并尽可能从 n 迭代到 0(生成大约少 2 个 asm 指令)for(int i=0; i&lt;n; i++) -> for(int i(n); i&gt;0; --i)

第四 - 如果您有 if()...else if()...else if() 链,请考虑使用 switch()。在大多数情况下,编译器都会为它们创建一个查找表。但我相信switch 可以保证这样做,但if 链却不行。简而言之 - switch() 最有可能比 if

第五 - 如果你必须使用向量,并且必须用一些值填充它们,要么使用&lt;algorithm&gt; 和迭代器,或者使用它附带的C++11vector::data() 来获取指向分配数组的指针,并对其进行迭代。

如果您不了解“如何”或“为什么”,请进行一些研究。如果您已经这样做但仍然不明白,那么我无法为您提供更多帮助 - 我不会为您优化代码。这样你就什么也学不到了。

此外,当给定的优化似乎不够优化时,请考虑考虑新算法。

【讨论】:

以上是关于图形编辑器编程挑战解决时间限制超过c ++ [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

应用程序池DefaultAppPool提供服务的进程关闭时间超过了限制的解决办法

解决为应用程序池 提供服务的进程关闭时间超过了限制

在 iMac 上做 C 教程,遇到挑战 [关闭]

解决方案电影标题中缺少代码的片段,完成挑战更多[关闭]

2018“氢舞杯”编程挑战赛2

NowCoderWannafly挑战赛5-可编程拖拉机比赛-向上取整和向下取整函数