题目是对RLE压缩的图像进行边缘检测。
RLE是游程编码的意思(Run length edcoding),比如555555根据游程编码可以编码成5 6。在代码中可以用控制符来区分编码字节和重复次数。
题目大意如下:
输入一张或多张游程编码的压缩图片,输出该图片的边缘检测的图片。其中,输入时0表示没有下一张图片,0 0表示本张图片输入结束。
算法思路:
1)输入的为RLE压缩图像,需要将图像还原为bitmap的形式才能计算图像的边缘检测。
缺点:如果图像过大,比如达到了10^9个像素,那么需要创建的二位数组将会超出题目给定内存的限制
优化:建立一个view,大小为3*column,这样每次只用存3行的像素,并且对于中间的一行,上下文都是可见的,因此可以做到逐行解析,逐行处理
2)根据上面的改进方法,无论多大的图像只要时间足够,都是可以计算出边缘检测图形的,但是也有缺点
缺点:逐行处理所花的时间会随着图像的增大而变多,当图形足够大的时候,时间会增到到超出限制。如果图像中重复单元很多,存在很大的优化空间。
优化:检测输入的像素,如果输入的重复像素过多,可以计算出有多少像素的边缘检测值是一样的,那么可以省去这些像素的计算
整体代码如下:
import java.io.*; public class Main { public static void main(String[] args) throws IOException, InvalidInputException { BufferedReader stdin = new BufferedReader( new InputStreamReader(System.in)); String line = null; String[] input = null; while (true) { line = stdin.readLine(); int width = Integer.parseInt(line); if (width == 0) break; int[][] matrix = new int[3][width]; RlePair pair = new RlePair(0, 0); int value = 0; int times = 0; int index = 0; int delta = 0; int diffValue = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < width; j++) { matrix[i][j] = -1; // -1 is null } } while (true) { line = stdin.readLine(); input = line.split("\\s"); if (input.length != 2) { throw new InvalidInputException(); } value = Integer.parseInt(input[0]); times = Integer.parseInt(input[1]); if (value == 0 && times == 0) break; int currRow = 0; //----------------------------------------------------------------- // 算法主体 for (int n = 0; n < times; n++) { currRow = (index + n) / width + 1 - delta; if (currRow == 3) { for (int i = 0; i < width; i++) { if (matrix[1][i] == -1) break; diffValue = max(width, matrix, i); if (diffValue == pair.value) { pair.times++; } else { if (pair.times != 0) System.out.println(pair.toString()); pair = new RlePair(diffValue, 1); } } delta++; for (int i = 0; i < 2; i++) { for (int j = 0; j < width; j++) { matrix[i][j] = matrix[i + 1][j]; } } currRow = (index + n) / width + 1 - delta; if (n / width > 2 && (times - n) / width > 1) { int d = (times - n) / width - 1; pair.times += d * width; n += d * width; delta += d; } } matrix[currRow][(index + n) % width] = value; } index += times; } // 算法主体 //----------------------------------------------------------------- // 最后几行的处理 for (int i = 0; i < width; i++) { if (matrix[1][i] == -1) break; diffValue = max(width, matrix, i); if (diffValue == pair.value) { pair.times++; } else { if (pair.times != 0) System.out.println(pair.toString()); pair = new RlePair(diffValue, 1); } } for (int i = 0; i < 2; i++) { for (int j = 0; j < width; j++) { matrix[i][j] = matrix[i + 1][j]; } } for (int j = 0; j < width; j++) { matrix[2][j] = -1; } for (int i = 0; i < width; i++) { if (matrix[1][i] == -1) break; diffValue = max(width, matrix, i); if (diffValue == pair.value) { pair.times++; } else { if (pair.times != 0) System.out.println(pair.toString()); pair = new RlePair(diffValue, 1); } } System.out.println(pair.toString()); System.out.println("0 0"); // 最后几行的处理 //----------------------------------------------------------------- } if (stdin != null) { stdin.close(); stdin = null; } } private static int max(int width, int[][] matrix, int index) { // TODO Auto-generated method stub // 0: 0 1 2 // 1: 3 4 // 2: 5 6 7 int[] x = new int[] {-1, -1, -1, -1, -1, -1, -1, -1}; // 8 if (index - 1 >= 0) { x[0] = matrix[0][index - 1]; x[3] = matrix[1][index - 1]; x[5] = matrix[2][index - 1]; } x[1] = matrix[0][index]; x[6] = matrix[2][index]; if (index + 1 < width) { x[2] = matrix[0][index + 1]; x[4] = matrix[1][index + 1]; x[7] = matrix[2][index + 1]; } int maxDiff = 0; for (int n : x) { if (n != -1) { maxDiff = maxDiff > Math.abs(matrix[1][index] - n) ? maxDiff : Math.abs(matrix[1][index] - n); } } return maxDiff; } } class RlePair { int value; int times; public RlePair(int value, int times) { this.value = value; this.times = times; } @Override public String toString() { // TODO Auto-generated method stub return this.value + " " + this.times; } } @SuppressWarnings("serial") class InvalidInputException extends Exception { }
让我郁闷的是,代码提交poj一直是runtime error,而自己测试确没什么问题。我测试的环境是jdk7.0,不知道和jdk升级是否有关系。。。(狡辩一下:我练习的目标是训练自己思考算法的感觉的,此题的目的已经达到,如果poj能多给一点错误信息我是很乐意让这道题accept的:))