矩阵合法化

第一次参加英雄会,感觉挺有意思的。由于超时,写的code没有拿去竞赛。现在晒出来,一为纪念下,二为让大家指出来不对之处。


题目

在n*m的01矩阵中,如果一块连通的1中任何两个1的最小距离等于他们下标的距离减一,那么这个全1连通块就是合法的。现在给你一个01矩阵,请你计算出将它的所有全1连通块都变成合法的所需改变的最少的0的个数(将0变成1)。两个元素的最小距离就是一个元素在连通块里走到另一个元素所经过的最少的元素的个数(不包括这两个元素),下标的距离就是abs(x1-x2)+abs(y1-y2). 例如:0111110 在这个矩阵中11111就是一个连通块,最左边的1到最右边的1的距离就是3,他们下标的距离是4。 输入描述: 输入包含多组测试数据,每组测试数据包含n+1行,第一行为一个正整数n,m(0<n,m<=50));接下来就是n*m的01矩阵。 输出描述: 输出包含一个数就是改变最少的0的个数。 

挑战规则:  

输入样例: 3 3 100 101 111 3 3 111 101 101 输出样例: 1 2 


大致思路是:现将矩阵分成多个segment,然后再对每个segment进行合法化:从segment的开头或尾巴开始


import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Test {

	private static int rows;
	private static int cols;
	private static Test test = new Test();

	public static void main(String[] args) {

		Scanner scanner = new Scanner(System.in);
		String line = null;
		boolean isNewData = true;
		int lineNum = 0;
		List<List<Cell>> cellsList = new ArrayList<List<Cell>>();
		List<Cell> cellList = new ArrayList<Test.Cell>();
		while (!"OK".equals(line = scanner.nextLine())) {
			if (!isNewData) {
				char[] datas = line.toCharArray();
				cellList.addAll(generateCellList(lineNum, datas));
				lineNum++;
			}
			if (lineNum == rows) {
				cellsList.add(cellList);
				isNewData = true;
				lineNum = 0;
			}
			if (line.contains(" ")) {
				String[] numbers = line.split(" ");
				rows = Integer.valueOf(numbers[0]);
				cols = Integer.valueOf(numbers[1]);
				isNewData = false;
				cellList = new ArrayList<Test.Cell>();
			}
		}

		for (List<Cell> lst : cellsList) {
			int step = getStep(lst);
			System.out.println(step);
		}

	}

	private static List<Cell> generateCellList(int lineNum, char[] datas) {
		List<Cell> cells = new ArrayList<Test.Cell>();
		for (int i = 0; i < datas.length; i++) {
			boolean value = datas[i] == '1';
			cells.add(test.new Cell(lineNum, i, value));
		}
		return cells;
	}

	private static int getStep(List<Cell> cellList) {
		List<Segment> segmentCells = getSegment(cellList);

		int segmengtLen = segmentCells.size();

		if (segmengtLen == 1) {
			Segment segmentCell = segmentCells.get(0);
			if ((segmentCell.right.col == cols - 1)
					&& (segmentCell.right.row == rows - 1)) {
				return getLeftSteps(segmentCell);
			}
		}
		return getRightSteps(segmentCells, segmengtLen);
	}

	private static int getLeftSteps(Segment segmentCell) {
		int steps = 0;
		Segment current = segmentCell;
		if (current.isValid()) {
			return steps;
		}
		Cell myExpectedCell = getExpectedLeftCell(segmentCell);
		if (myExpectedCell == null) {
			return steps;
		}
		steps += getSteps(myExpectedCell, current.left);
		return steps;
	}

	private static int getRightSteps(List<Segment> segmentCells,
			int segmengtLen) {
		int steps = 0;
		for (int i = 0; i < segmengtLen; i++) {
			Segment current = segmentCells.get(i);
			if (current.isValid()) {
				continue;
			}
			Cell myExpectedCell = getRightExpectedCell(current);
			if (myExpectedCell == null) {
				continue;
			}
			steps += getSteps(current.right, myExpectedCell);

			Segment next = null;
			if (i + 1 < segmengtLen) {
				next = segmentCells.get(i + 1);
			}
			if (next != null && checkConfilct(myExpectedCell, next.left)) {
				i++;
			}
		}
		return steps;
	}

	private static boolean checkConfilct(Cell left, Cell right) {
		if (right.row > left.row) {
			return false;
		} else if (right.row == left.row) {
			return right.col <= left.col;
		}
		return true;
	}

	private static int getSteps(Cell right, Cell expectedCell) {
		int factor = 1;
		if (expectedCell.row > right.row) {
			factor = (expectedCell.row - right.row) * cols;
		}
		return (expectedCell.col - right.col) * factor;
	}

	private static Cell getRightExpectedCell(Segment segmentCell) {
		Cell left = segmentCell.left;
		Cell right = segmentCell.right;

		for (int rowIndex = right.row; rowIndex < rows; rowIndex++) {
			int startCol = (rowIndex == right.row) ? right.col + 1 : 0;
			for (int colIndex = startCol; colIndex < cols; colIndex++) {				
				int ValidNumberDistance = Math.abs((rowIndex * cols + colIndex)
						- (left.row * cols + left.col) - 1);
				int distanceForAxis = Math.abs(colIndex - left.col)
						+ Math.abs(rowIndex - left.row);

				if (ValidNumberDistance >= (distanceForAxis - 1)) {
					return test.new Cell(rowIndex, colIndex, false);
				}
			}
		}
		return null;
	}

	private static Cell getExpectedLeftCell(Segment segmentCell) {

		Cell left = segmentCell.left;
		Cell right = segmentCell.right;
		for (int row = left.row; row >= 0; row--) {
			int startCol = (row == left.row) ? left.col - 1 : cols - 1;
			for (int col = startCol; col >= 0; col--) {
				int ValidNumberDistance = Math
						.abs((right.row * cols + right.col)
								- (row * cols + col) - 1);
				int distanceForAxis = Math.abs(right.row - row)
						+ Math.abs(right.col - col);

				if (ValidNumberDistance >= (distanceForAxis - 1)) {
					return test.new Cell(row, col, false);
				}
			}
		}
		return null;

	}

	private static List<Segment> getSegment(List<Cell> cellList) {
		List<Segment> segmentCells = new ArrayList<Segment>();
		int leftIndex = 0;
		int rightIndex = 0;
		int currentIndex = 0;
		boolean leftExistingFlag = false;
		Cell leftCell = null;
		int listSize = cellList.size();
		for (Cell cell : cellList) {

			if (cell.value && !leftExistingFlag) {
				leftIndex = currentIndex;
				leftExistingFlag = true;
				leftCell = cell;
			}
			if ((!cell.value || currentIndex == listSize - 1)
					&& leftExistingFlag) {
				rightIndex = currentIndex - 1;
				leftExistingFlag = false;
				if (rightIndex > leftIndex && leftCell != null) {
					final Cell rightCell = currentIndex == listSize - 1 ? cell
							: cellList.get(rightIndex);
					Segment segment = test.new Segment(leftCell,
							rightCell);
					segmentCells.add(segment);
				}
			}
			currentIndex++;
		}
		return segmentCells;
	}

	public class Segment {
		Cell left;
		Cell right;

		public Segment(Cell left, Cell right) {
			this.left = left;
			this.right = right;
		}

		public boolean isValid() {
			int factor = 1;
			if (right.col > left.col) {
				factor = (right.col - left.col) * cols;
			}
			int ValidNumberDistance = (right.row - left.row - 2) * factor;
			int distanceForAxis = Math.abs(right.row - left.row)
					+ Math.abs(right.col - left.col);
			return (distanceForAxis - 1) == ValidNumberDistance;
		}
	}

	public class Cell {
		int row;
		int col;
		boolean value;

		public Cell(int x, int y, boolean value) {
			this.row = x;
			this.col = y;
			this.value = value;
		}
	}
}


你可能感兴趣的:(矩阵合法化)