POJ1009 Edge Detection

题目来源:http://poj.org/problem?id=1009

题目大意:

  某图像公司用run length encoding(RLE)的方式记录和存储了大量的图像。程序的目标是读入压缩后的图像,对图像进行边缘检测,然后输出另一幅压缩后的图片。具体形式见下面的图片和描述。

  一种最简单的边缘检测算法就是使输出图片像素点的值为输入图片中该像素点与其周围像素点值之间差值的最大值。考虑下面的例子:

Output image中左上角的像素点的值是|15-15|,|15-100|和|15-100|的最大值85.第4行第2列的像素点值是|175-100|,|175-100|,|175-100|,|175-175|,|175-25|,|175-175|,|175-175|和|175-25|的最小值150.

图像的像素点数在2至1,000,000,000(109)之间。所有的图片以RLE(run length encoding)的方式进行压缩编码。RLE是一些数据对,每对含一个像素值v和一个run length,即有连续多少个点的像素点的值为v。每幅图像最多含有1000个RLE对。连续的数据对的像素值都不相同。图像的每行像素点数相同。

输入:含一张或多张图像,每张图像信息的第一行为图像的宽度,接下来的每行为一个RLE对,以0 0结尾。图像宽度为0时表示图像数据输入完毕。Example Input展示的即为上图所示的图像。

输出:一系列边缘检测后的图像。与输入图像的格式相同,但运行RLE的数目多于1000.


Sample Input

7
15 4
100 15
25 2
175 2
25 5
175 2
25 5
0 0
10
35 500000000
200 500000000
0 0
3
255 1
10 1
255 2
10 1
255 2
10 1
255 1
0 0
0

Sample Output

7
85 5
0 2
85 5
75 10
150 2
75 3
0 2
150 2
0 4
0 0
10
0 499999990
165 20
0 499999990
0 0
3
245 9
0 0
0

刚开始直接用暴力方法做,发现数据量大时计算时间过长,TLE了。后来看了牛人的方法表示无比佩服。

  对于本题有如下观察:

  1.由于图片的像素点数最大为10^9,而RLE对的数目最大为1000,所以,一定存在一些RLE的run length很长,使得图像中有比较多的连续像素值相等,也即对他们的很多点进行边缘检测后的值一定为0,所以不必再逐个计算。

  2.实际上我们只需要关注结果值会与其前面的点不一样的点即可(取名为关键点),由这些关键点即可得到输出图像的RLE对。

  对于第2点,哪些点会是关键点呢?大牛分析后发现,每个输入的RLE对的起点和终点以及这些点周围的点一定包含了所有的关键点。如何证明?我没有去想怎么从理论上严格的推倒,只是从直觉上,我觉得可以这样来想象这个问题:

  首先把整幅图想象成一张白纸(比如把全部像素点的值初始化为0)。每读入一个RLE对,就相当于用彩笔在纸上给指定数目的像素点涂上了颜色。而每多涂一次颜色,该次涂色的起点和终点处及其周边的点的输出值会受到影响,有可能会变得跟其前一个点的输出值不一样(这个在纸上试一试就能发现),也就是说有可能成为关键点。而其他点的输出值应该是跟其左边的点输出值相等。所以当处理完了每个RLE对,也就把所有可能成为关键点的点的输出值都计算出来了。然后按坐标将所有点排序,再把输出值相等的点合并起来,就可以得到输出的RLE对。

  具体实现可以下列参考代码,但是效率可能不是很高,应该还可以继续优化。

  1 //////////////////////////////////////////////////////////////////////////
  2 //        POJ1009 Edgee Detection
  3 //        Memory: 656K        Time: 172MS
  4 //        Language: C++        Result: Accepted
  5 //////////////////////////////////////////////////////////////////////////
  6 
  7 #include <iostream>
  8 #include <map>
  9 #include <math.h>
 10 #include <stdlib.h>
 11 
 12 #define getBigger(a, b) ((a > b) ? a : b)
 13 #define upLeft(i)  (i - c - 1)
 14 #define up(i)  (i - c)
 15 #define upRight(i)  (i - c + 1)
 16 #define left(i)  (i - 1)
 17 #define right(i)  (i + 1)
 18 #define downLeft(i)  (i + c - 1)
 19 #define down(i)  (i + c)
 20 #define downRight(i)  (i + c + 1)
 21 
 22 using namespace std;
 23 
 24 class RLE {
 25 public:
 26     int color;
 27     int length;
 28     int startPoint;
 29     int endPoint;
 30 };
 31 
 32 RLE RLEList[1000];
 33 int n;//RLE表长度
 34 int pointCount; //总点数
 35 int c, r;//image的列数与行数
 36 map<int, int> PVmap;
 37 
 38 int getColor(int index) {
 39     for(int i = 0; i < n; i++) {
 40         if (index <= RLEList[i].endPoint) {
 41             return RLEList[i].color;
 42         } else {
 43             continue;
 44         }
 45     }
 46 } 
 47 
 48 int getValue(int i) {
 49     int value = 0;
 50 
 51     if ((upLeft(i) >= 0) && ((i % c) > 0)) {
 52         value = getBigger(value, abs(getColor(i) - getColor(upLeft(i))));
 53     }
 54     if ((up(i) >=  0)) {
 55         value = getBigger(value, abs(getColor(i) - getColor(up(i))));
 56     }
 57     if ((upRight(i) >= 0) && ((i % c) < c - 1)) {
 58         value = getBigger(value, abs(getColor(i) - getColor(upRight(i))));
 59     }
 60     if ((left(i) >= 0) && ((i % c) > 0)) {
 61         value = getBigger(value, abs(getColor(i) - getColor(left(i))));
 62     }
 63     if ((right(i) <= r * c - 1) && ((i % c) < c - 1)) {
 64         value = getBigger(value, abs(getColor(i) - getColor(right(i))));
 65     }
 66     if ((downLeft(i) <= r * c - 1) && ((i % c) > 0)) {
 67         value = getBigger(value, abs(getColor(i) - getColor(downLeft(i))));
 68     }
 69     if ((down(i) <= r * c - 1)) {
 70         value = getBigger(value, abs(getColor(i) - getColor(down(i))));
 71     }
 72     if ((downRight(i) <= r * c - 1) && ((i % c) < c - 1)) {
 73         value = getBigger(value, abs(getColor(i) - getColor(downRight(i))));
 74     }
 75     return value;
 76 }
 77 
 78 void processPos(int index) {
 79     if (PVmap.find(index) == PVmap.end()) {
 80         PVmap[index] = getValue(index);
 81     }
 82     if (upLeft(index) >=0 && upLeft(index) < pointCount) {
 83         if (PVmap.find(upLeft(index)) == PVmap.end()) {
 84             PVmap[upLeft(index)] = getValue(upLeft(index));
 85         }
 86     }
 87     if (up(index) >=0 && up(index) < pointCount) {
 88         if (PVmap.find(up(index)) == PVmap.end()) {
 89             PVmap[up(index)] = getValue(up(index));
 90         }
 91     }
 92     if (upRight(index) >=0 && upRight(index) < pointCount) {
 93         if (PVmap.find(upRight(index)) == PVmap.end()) {
 94             PVmap[upRight(index)] = getValue(upRight(index));
 95         }
 96     }
 97     if (left(index) >=0 && left(index) < pointCount) {
 98         if (PVmap.find(left(index)) == PVmap.end()) {
 99             PVmap[left(index)] = getValue(left(index));
100         }
101     }
102     if (right(index) >=0 && right(index) < pointCount) {
103         if (PVmap.find(right(index)) == PVmap.end()) {
104             PVmap[right(index)] = getValue(right(index));
105         }
106     }
107     if (downLeft(index) >=0 && downLeft(index) < pointCount) {
108         if (PVmap.find(downLeft(index)) == PVmap.end()) {
109             PVmap[downLeft(index)] = getValue(downLeft(index));
110         }
111     }
112     if (down(index) >=0 && down(index) < pointCount) {
113         if (PVmap.find(down(index)) == PVmap.end()) {
114             PVmap[down(index)] = getValue(down(index));
115         }
116     }
117     if (downRight(index) >=0 && downRight(index) < pointCount) {
118         if (PVmap.find(downRight(index)) == PVmap.end()) {
119             PVmap[downRight(index)] = getValue(downRight(index));
120         }
121     }
122 }
123 
124 int main(void) {
125     c = 0;
126     while (true) {
127         cin >> c;
128         if (c == 0) {
129             cout << "0" << endl;
130             return 0;
131         }
132         pointCount = 0;
133         int i = 0;
134         while (true) {
135             int color, length;
136             cin >> color >> length;
137             if (length == 0) {
138                 break;
139             }
140             RLEList[i].color = color;
141             RLEList[i].length = length;
142             i++;
143             pointCount += length;
144         }
145         r = pointCount / c;
146         if (pointCount % c) {
147             r++;
148             RLEList[i].length = r * c - pointCount;
149             RLEList[i].color = 0;
150             pointCount = r * c;
151             i++;
152         }
153         n = i;
154         RLEList[0].startPoint = 0;
155         RLEList[0].endPoint = RLEList[0].length - 1;    
156         for (int i = 1; i < n; i++) {
157             RLEList[i].startPoint = RLEList[i - 1].startPoint + RLEList[i - 1].length;
158             RLEList[i].endPoint = RLEList[i - 1].endPoint + RLEList[i].length;
159         }
160         cout << c << endl;
161         //处理每个RLE对的起点和终点产生的影响
162         for (int RLEIndex = 0; RLEIndex < n; RLEIndex++) {
163             int startPos = RLEList[RLEIndex].startPoint;
164             int endPos = RLEList[RLEIndex].endPoint;
165             processPos(startPos);
166             processPos(endPos);            
167         }
168         map<int, int>::iterator it1;
169         map<int, int>::iterator it2;
170         int l = 1;
171         //合并output image中相同的关键点,输出RLE对
172         for (it1 = PVmap.begin(), it2 = it1, ++it2; it2 != PVmap.end(); ++it1, ++it2) {
173             if((*it2).second == (*it1).second) {
174                 l += (*it2).first - (*it1).first;
175             } else {
176                 cout << (*it1).second << " " << l << endl;
177                 l = 1;
178             }
179         }
180         --it2;
181         cout << (*it2).second << " " << l << endl;
182         cout << "0 0"<< endl;    
183         PVmap.clear();
184     }
185     return 0;
186 }
View Code 
posted @ 2013-07-30 22:35  小菜刷题史  阅读(553)  评论(0编辑  收藏  举报