图形编辑器编程挑战解决时间限制超过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<n; i++)
-> for(int i(n); i>0; --i)
第四 - 如果您有 if()...else if()...else if()
链,请考虑使用 switch()
。在大多数情况下,编译器都会为它们创建一个查找表。但我相信switch
可以保证这样做,但if
链却不行。简而言之 - switch()
最有可能比 if
快
第五 - 如果你必须使用向量,并且必须用一些值填充它们,要么使用<algorithm>
和迭代器,或者使用它附带的C++11
和vector::data()
来获取指向分配数组的指针,并对其进行迭代。
如果您不了解“如何”或“为什么”,请进行一些研究。如果您已经这样做但仍然不明白,那么我无法为您提供更多帮助 - 我不会为您优化代码。这样你就什么也学不到了。
此外,当给定的优化似乎不够优化时,请考虑考虑新算法。
【讨论】:
以上是关于图形编辑器编程挑战解决时间限制超过c ++ [关闭]的主要内容,如果未能解决你的问题,请参考以下文章