我正在尝试编写一个程序来定位和计算网格中所有连接的区域。连接区域由一组标记的单元格(值1)组成,使得区域中的每个单元格可以通过从区域中的另一个标记的单元格向上,向下,向左或向右移动来到达,对角线上的单元格不被视为连接。 因此,需要输入:
10 20
0 1 1 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 1 0
0 1 1 1 0 1 1 0 0 1 0 0 1 1 1 0 0 0 1 1
0 0 1 0 0 0 1 1 0 1 0 0 0 1 0 0 0 1 1 1
1 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 1 0
1 1 0 1 0 0 0 1 1 1 0 0 0 1 1 0 1 1 0 0
1 1 1 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 0 1 1 0 1 0 0 0
0 1 1 1 1 1 0 0 1 1 1 0 0 0 1 1 1 1 1 0
0 0 0 1 1 0 0 0 0 1 0 0 0 1 1 0 0 1 1 0
1 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 0 1 0 0
输出:
0 1 1 0 0 0 2 0 3 3 0 0 0 0 4 0 0 0 5 0
0 1 1 1 0 2 2 0 0 3 0 0 4 4 4 0 0 0 5 5
0 0 1 0 0 0 2 2 0 3 0 0 0 4 0 0 0 5 5 5
6 0 0 0 0 0 0 0 3 3 0 0 7 0 0 0 5 5 5 0
6 6 0 6 0 0 0 3 3 3 0 0 0 8 8 0 5 5 0 0
6 6 6 6 0 0 0 0 0 0 9 0 8 8 8 0 0 0 0 0
0 6 6 6 0 0 0 9 9 9 9 0 0 8 8 0 8 0 0 0
0 6 6 6 6 6 0 0 9 9 9 0 0 0 8 8 8 8 8 0
0 0 0 6 6 0 0 0 0 9 0 0 0 8 8 0 0 8 8 0
10 0 6 6 6 6 6 0 0 0 0 0 0 0 8 8 0 8 0 0
现在,当我运行代码时,我得到:
0 2 2 0 0 0 2 0 2 2 0 0 0 0 2 0 0 0 2 0
0 3 3 3 0 3 3 0 0 3 0 0 3 3 3 0 0 0 3 3
0 0 4 0 0 0 4 4 0 4 0 0 0 4 0 0 0 4 4 4
5 0 0 0 0 0 0 0 5 5 0 0 5 0 0 0 5 5 5 0
6 6 0 6 0 0 0 6 6 6 0 0 0 6 6 0 6 6 0 0
7 7 7 7 0 0 0 0 0 0 7 0 7 7 7 0 0 0 0 0
0 8 8 8 0 0 0 8 8 8 8 0 0 8 8 0 8 0 0 0
0 9 9 9 9 9 0 0 9 9 9 0 0 0 9 9 9 9 9 0
0 0 0 10 10 0 0 0 0 10 0 0 0 10 10 0 0 10 10 0
11 0 11 11 11 11 11 0 0 0 0 0 0 0 11 11 0 11 0 0
这是我的代码:
package project2;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;
public class Project2 {
private static int height;
private static int length;
public static void main(String[] args) {
String inputFile;
Scanner input = new Scanner(System.in);
System.out.print("Enter input file name: ");
inputFile = "test_case_proj2.txt";
try {
Integer grid[][] = loadGrid(inputFile);
System.out.println("Before flood fill");
printGrid(grid);
findGroups(grid, 0, 0, 2, height, length);
System.out.println("After flood fill");
printGrid(grid);
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
public static void findGroups(Integer[][] array, int column, int row,
int counter, int height, int length) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < length; j++) {
if (row < 0 || row >= length || column < 0 || column >= height) {
} else {
if (array[column][j] == 1) {
array[column][j] = counter;
findGroups(array, column, row + 1, counter, height, length);
findGroups(array, column, row - 1, counter, height, length);
findGroups(array, column - row, j, counter, height, length);
findGroups(array, column + row, j, counter, height, length);
}
}
}
counter++;
column++;
row++;
}
}
public static Integer[][] loadGrid(String fileName) throws IOException {
FileInputStream fin;
fin = new FileInputStream(fileName);
Scanner input = new Scanner(fin);
height = input.nextInt();
length = input.nextInt();
Integer grid[][] = new Integer[height][length];
for (int r = 0; r < height; r++) {
for (int c = 0; c < length; c++) {
grid[r][c] = input.nextInt();
}
}
fin.close();
return (grid);
}
public static void printGrid(Integer[][] grid) {
for (Integer[] grid1 : grid) {
for (int c = 0; c < grid[0].length; c++) {
System.out.printf("%3d", grid1[c]);
}
System.out.println();
}
}
}
有人看到我做错了吗?
答案 0 :(得分:4)
你将过多的责任放在一个方法中。您可以将填充算法与岛编号算法结合使用。
我已经创建了这个jdoodle。
首先,你最好创建一个fill
方法,除了用计数器的值填充岛屿之外别无他法(我已经将它设置为静态,所以你不需要通过算法传递它,虽然这是任意的):
public static void fill(Integer[][] array, int column, int row, int height, int length) {
if (row >= 0 && row < length && column >= 0 && column < height && array[column][row] == 1) {
array[column][row] = counter;
fill(array, column, row + 1, height, length);
fill(array, column, row - 1, height, length);
fill(array, column - 1, row, height, length);
fill(array, column + 1, row, height, length);
}
}
如您所见,这是一种使用递归的简单算法。
其次,您只需创建一个在所有可能的切片上调用fill
算法的方法。如果你到达一个值为1
的点,你知道这个岛还没有被另一个国王声称:D。因此,您填写它并使用counter
id向国王索取。通常,使用特殊的布尔数组来阻止fill
算法进入无限循环。您通过开始从索引counter = 2
分配号码来巧妙地解决了这个问题,当然,一旦所有岛屿被声明,您需要递减该值。
public static void findGroups(Integer[][] array, int column, int row, int height, int length) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < length; j++) {
if (array[i][j] == 1) {
fill(array, i,j, height, length);
counter++;
}
}
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < length; j++) {
if (array[i][j] > 1) {
array[i][j]--;
}
}
}
}
算法的其余部分保持不变(算法现在从stdin
读取,但这只是为了确保jdoodle继续工作)。
关于你的算法,很难理解。例如,您使用填充,部分调用使用column
和row
,其他部分使用j
。接下来,您的计数器仅针对每行进行更新。如果两个idlands从同一行开始(如您的输出所示),这会导致问题。