The following algorithm will solve your problem. You can also use memoization to speed up work time. The idea is simple:
- when opening parentheses increases the number of open brackets;
- If you close a star, you must continue to close and increase closed parentheses;
- If you close, and the number of closed parentheses is greater than or equal to the number of open brackets, stop and return this value.
The rest of the code is syntactic sugar. (From the returned list of visited items, trivially complete the output you want).
import java.util.LinkedList; import java.util.List; public class USACO { static class Path { public List<String> items; public int value; public Path() { this.items = new LinkedList<String>(); this.value = 0; } } public static void main(final String[] args) { final int n = 5; final String[][] input = new String[n][n]; // Create a random input of size n for (int y = 0; y < n; y++) { for (int x = 0; x < n; x++) { input[y][x] = Math.random() < 0.5 ? "(" : ")"; System.out.print(input[y][x] + " "); } System.out.println(); } final Path bestPath = longestPath(n, input, 0, 0, 0, 0, input[0][0] == "("); System.out.println("Max:" + bestPath.value + "\n" + bestPath.items); } public static Path longestPath(final int n, final String[][] input, final int x, final int y, int numberOpened, int numberClosed, final boolean wasOpening) { if (input == null) { return new Path(); } else if (!wasOpening && (numberClosed >= numberOpened)) { // Reached a solution final Path path = new Path(); path.value = numberOpened; path.items.add("(" + x + "," + y + ")"); return path; } else if ((x < 0) || (y < 0) || (x >= n) || (y >= n)) { // Out of bound return new Path(); } else if (input[y][x] == "") { // Already visited this item return new Path(); } else { final String parenthese = input[y][x]; // Increment the number of consecutive opened or closed visited if (parenthese.equals("(")) { numberOpened++; } else { numberClosed++; } input[y][x] = ""; // Mark as visited Path bestPath = new Path(); bestPath.value = Integer.MIN_VALUE; // Explore the other items for (int dy = -1; dy <= 1; dy++) { for (int dx = -1; dx <= 1; dx++) { if (((dy == 0) || (dx == 0)) && (dy != dx)) { // go only up, down, left, right final boolean opening = (parenthese == "("); if (wasOpening || !opening) { // Find the longest among all the near items final Path possiblePath = longestPath(n, input, x + dx, y + dy, numberOpened, numberClosed, opening); if (possiblePath.value > bestPath.value) { bestPath = possiblePath; bestPath.items.add("(" + x + "," + y + ")"); } } } } } input[y][x] = parenthese; // mark as not visited return bestPath; } }
}
source share