Water capacity of a 2D array - java

I have to do a little exercise at my university but I am already stuck for a while. The exercise is about calculating the water capacity of a 2D array, the user has to enter the width (w) and the height (h) of the 2D array, and then all the elements of the array, which represent the height at that location. Really simple example:
10 10 10
10 2 10
10 10 10
The output will then be 8, because that is the maximum water that fits in there. Another example is:
6 4
1 5 1 5 4 3
5 1 5 1 2 4
1 5 1 4 1 5
3 1 3 6 4 1
Output will be 14.
What also important to mention is: The width and height of the array can not be larger than 1000 and the heights of the element cannot be larger than 10^5.
Now I basically have the solution, but it is not fast enough for larger inputs. What I did is the following: I add the heights to a TreeSet and then every time I poll the last one (the highest) and then I go through the array (not looking at the edges) and use DFS and check for every position if the water can stay in there. If the water doesn't go out of the array than calculate the positions that are under water, if it goes out of the array then poll again and do the same.
I also tried looking at the peaks in the array, by going vertically and horizontally. For the example above you get this:
0 5 0 5 4 0
5 0 5 0 0 4
0 5 0 4 0 5
3 1 3 6 4 0
What I did with this was give the peaks a color let say (black) and then for all the white colors take the minimum peak value with DFS again and then take that minimum to calculate the water capacity. But this doesn't work, because for example:
7 7 7 7 7
7 4 4 4 7
7 2 3 1 7
7 4 4 4 7
7 7 7 7 7
Now 3 is a peak, but the water level is 7 everywhere. So this won't work.
But because my solution is not fast enough, I am looking for a more efficient one. This is the part of the code where the magic happens:
while (p.size() != 0 || numberOfNodesVisited!= (w-2)*(h-2)) {
max = p.pollLast();
for (int i=1; i < h-1; i++) {
for (int j=1; j < w-1; j++) {
if (color[i][j] == 0) {
DFSVisit(profile, i, j);
if (!waterIsOut) {
sum+= solveSubProblem(heights, max);
numberOfNodesVisited += heights.size();
for(int x = 0; x < color.length; x++) {
color2[x] = color[x].clone();
}
} else {
for(int x = 0; x < color2.length; x++) {
color[x] = color2[x].clone();
}
waterIsOut = false;
}
heights.clear();
}
}
}
}
Note I am resetting the paths and the colors every time, I think this is the part that has to be improved.
And my DFS: I have three colors 2 (black) it is visited, 1 (gray) if it is an edge and 0 (white) if is not visited and not an edge.
public void DFSVisit(int[][] profile, int i, int j) {
color[i][j] = 2; // black
heights.add(profile[i][j]);
if (!waterIsOut && heights.size() < 500) {
if (color[i+1][j] == 0 && max > profile[i+1][j]) { // up
DFSVisit(profile, i+1, j);
} else if (color[i+1][j] == 1 && max > profile[i+1][j]) {
waterIsOut = true;
}
if (color[i-1][j] == 0 && max > profile[i-1][j]) { // down
DFSVisit(profile, i-1, j);
} else if (color[i-1][j] == 1 && max > profile[i-1][j]) {
waterIsOut = true;
}
if (color[i][j+1] == 0 && max > profile[i][j+1]) { // right
DFSVisit(profile, i, j+1);
} else if (color[i][j+1] == 1 && max > profile[i][j+1]) {
waterIsOut = true;
}
if (color[i][j-1] == 0 && max > profile[i][j-1]) { //left
DFSVisit(profile, i, j-1);
} else if (color[i][j-1] == 1 && max > profile[i][j-1]) {
waterIsOut = true;
}
}
}
UPDATE
#dufresnb referred to talentbuddy.co where the same exercise is given at https://www.talentbuddy.co/challenge/526efd7f4af0110af3836603. However I tested al lot of solutions and a few of them actually make it through my first four test cases, most of them however already fail on the easy ones. Talent buddy did a bad job on making test cases: in fact they only have two. If you want to see the solutions they have just register and enter this code (language C): it is enough to pass their test cases
#include <stdio.h>
void rain(int m, int *heights, int heights_length) {
//What tests do we have here?
if (m==6)
printf("5");
else if (m==3)
printf("4");
//Looks like we need some more tests.
}
UPDATE
#tobias_k solution is a working solution, however just like my solution it is not efficient enough to pass the larger input test cases, does anyone have an idea for an more efficient implementation?
Any ideas and help will be much appreciated.

Here's my take on the problem. The idea is as follows: You repeatedly flood-fill the array using increasing "sea levels". The level a node is first flooded will be the same level that the water would stay pooled over that node when the "flood" retreats.
for each height starting from the lowest to the highest level:
put the outer nodes into a set, called fringe
while there are more nodes in the fringe set, pop a node from the set
if this node was first reached in this iteration and its height is lesser or equal to the current flood height, memorize the current flood height for tha tnode
add all its neighbours that have not yet been flooded and have a height lesser or equal to the current flood height to the fringe
As it stands, this will have compexity O(nmz) for an n x m array with maximum elevation z, but with some optimization we can get it down to O(nm). For this, instead of using just one fringe, and each time working our way from the outside all the way inwards, we use multiple fringe sets, one for each elevation level, and put the nodes that we reach in the fringe corresponding to their own height (or the current fringe, if they are lower). This way, each node in the array is added to and removed from a fringe exactly once. And that's as fast as it possibly gets.
Here's some code. I've done it in Python, but you should be able to transfer this to Java -- just pretend it's executable pseudo-code. You can add a counter to see that the body of the while loop is indeed executed 24 times, and the result, for this example, is 14.
# setup and preparations
a = """1 5 1 5 4 3
5 1 5 1 2 4
1 5 1 4 1 5
3 1 3 6 4 1"""
array = [[int(x) for x in line.strip().split()]
for line in a.strip().splitlines()]
cols, rows = len(array[0]), len(array)
border = set([(i, 0 ) for i in range(rows)] +
[(i, cols-1) for i in range(rows)] +
[(0, i ) for i in range(cols)] +
[(rows-1, i) for i in range(cols)])
lowest = min(array[x][y] for (x, y) in border) # lowest on border
highest = max(map(max, array)) # highest overall
# distribute fringe nodes to separate fringes, one for each height level
import collections
fringes = collections.defaultdict(set) # maps points to sets
for (x, y) in border:
fringes[array[x][y]].add((x, y))
# 2d-array how high the water can stand above each cell
fill_height = [[None for _ in range(cols)] for _ in range(rows)]
# for each consecutive height, flood-fill from current fringe inwards
for height in range(lowest, highest + 1):
while fringes[height]: # while this set is non-empty...
# remove next cell from current fringe and set fill-height
(x, y) = fringes[height].pop()
fill_height[x][y] = height
# put not-yet-flooded neighbors into fringe for their elevation
for x2, y2 in [(x-1, y), (x, y-1), (x+1, y), (x, y+1)]:
if 0 <= x2 < rows and 0 <= y2 < cols and fill_height[x2][y2] is None:
# get fringe for that height, auto-initialize with new set if not present
fringes[max(height, array[x2][y2])].add((x2, y2))
# sum of water level minus ground level for all the cells
volume = sum(fill_height[x][y] - array[x][y] for x in range(cols) for y in range(rows))
print "VOLUME", volume
To read your larger test cases from files, replace the a = """...""" at the top with this:
with open("test") as f:
a = f.read()
The file should contain just the raw array as in your question, without dimension information, separated with spaces and line breaks.

talentbuddy.co has this problem as one of their coding tasks. It's called rain, if you make an account you can view other peoples solutions.
#include <iostream>
#include <vector>
bool check(int* myHeights, int x, int m, bool* checked,int size)
{
checked[x]=true;
if(myHeights[x-1]==myHeights[x] && (x-1)%m!=0 && !checked[x-1])
{
if(!check(myHeights,x-1,m,checked,size))return false;
}
else if((x-1)%m==0 && myHeights[x-1]<=myHeights[x])
{
return false;
}
if(myHeights[x+1]==myHeights[x] && (x+1)%m!=m-1 && !checked[x+1])
{
if(!check(myHeights,x+1,m,checked,size))return false;
}
else if((x+1)%m==m-1 && myHeights[x+1]<=myHeights[x])
{
return false;
}
if(myHeights[x-m]==myHeights[x] && (x-m)>m && !checked[x-m])
{
if(!check(myHeights,x-m,m,checked,size))return false;
}
else if((x-m)<m && myHeights[x-m]<=myHeights[x])
{
return false;
}
if(myHeights[x+m]==myHeights[x] && (x+m)<size-m && !checked[x+m])
{
if(!check(myHeights,x+m,m,checked,size))return false;
}
else if((x+m)>size-m && myHeights[x+m]<=myHeights[x])
{
return false;
}
return true;
}
void rain(int m, const std::vector<int> &heights)
{
int total=0;
int max=1;
if(m<=2 || heights.size()/m<=2)
{
std::cout << total << std::endl;
return;
}
else
{
int myHeights[heights.size()];
for(int x=0;x<heights.size();++x)
{
myHeights[x]=heights[x];
}
bool done=false;
while(!done)
{
done=true;
for(int x=m+1;x<heights.size()-m;++x)
{
if(x<=m || x%m==0 || x%m==m-1)
{
continue;
}
int lower=0;
if(myHeights[x]<myHeights[x-1])++lower;
if(myHeights[x]<myHeights[x+1])++lower;
if(myHeights[x]<myHeights[x-m])++lower;
if(myHeights[x]<myHeights[x+m])++lower;
if(lower==4)
{
++total;
++myHeights[x];
done=false;
}
else if(lower>=2)
{
bool checked[heights.size()];
for(int y=0;y<heights.size();++y)
{
checked[y]=false;
}
if(check(myHeights,x,m,checked,heights.size()))
{
++total;
++myHeights[x];
done=false;
}
}
}
}
}
std::cout << total << std::endl;
return;
}

Related

Lights Out - finding worst initial state

I have a task revolving around a small game, called Lights Out.
Game
The game consists of a board with dimensions 3x3, where each cell can either be 1 or 0, for example:
0 1 0
1 1 0
0 0 0
the game is said to be solved when all cells are 1, so:
1 1 1
1 1 1
1 1 1
and in each turn the user can click any cell which will flip its state and the state of the neighbors to the left, right, above and below (if they exist). So clicking on the cell in the middle of the first example board will yield:
0 0 0
0 0 1
0 1 0
Task
Now I have to find the worst possible initial board for the game and also figure out how many turns it needs to the solved state if played optimal.
Attempt
I tried to write a recursive solver which, given an initial board, finds the optimal sequence of turns to solve the game. And after that I wanted to feed it with all possible initial boards.
However, the recursion runs into a stack overflow. So I probably have to rewrite it in an iterative fashion. How can I do that?
Here is the code, as minimal complete example:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;
public class GameTest {
public static void main(String[] args) {
boolean[][] board = {
{false, false, false},
{false, true, false},
{false, false, false}
};
List<GameState> solutionPath = GameSolver.solve(board);
printSolutionPath(solutionPath);
}
private static void printSolutionPath(List<GameState> solutionPath) {
System.out.printf("Solution path uses %d turns%n", solutionPath.get(solutionPath.size() - 1).getTurns());
String turnProgression = solutionPath.stream()
.map(state -> String.format("[%d|%d]", state.getX(), state.getY()))
.collect(Collectors.joining(" -> "));
System.out.println("Turns are: " + turnProgression);
System.out.println("Board progression is:");
for (GameState state : solutionPath) {
System.out.println(state.boardToString());
System.out.println("-----");
}
}
private static class GameSolver {
public static List<GameState> solve(boolean[][] initialBoard) {
GameState state = new GameState(initialBoard);
return solve(state);
}
public static List<GameState> solve(GameState state) {
// Base case
if (state.isSolved()) {
return List.of(state);
}
// Explore all other solutions
List<List<GameState>> solutionPaths = new ArrayList<>();
boolean[][] board = state.getBoard();
for (int x = 0; x < board.length; x++) {
for (int y = 0; y < board[x].length; y++) {
solutionPaths.add(solve(new GameState(state, x, y)));
}
}
List<GameState> bestSolutionPath = Collections.min(solutionPaths, Comparator.comparingInt(solutionPath -> solutionPath.get(solutionPath.size() - 1).getTurns()));
bestSolutionPath.add(state);
return bestSolutionPath;
}
}
private static class GameState {
private boolean[][] board;
private int turns;
private int x;
private int y;
public GameState(boolean[][] board) {
this.board = board;
turns = 0;
x = -1;
y = -1;
}
public GameState(GameState before, int x, int y) {
board = before.board;
click(x, y);
turns++;
this.x = x;
this.y = y;
}
public boolean isSolved() {
for (boolean[] row : board) {
for (boolean state : row) {
if (!state) {
return false;
}
}
}
return true;
}
public int getTurns() {
return turns;
}
public boolean[][] getBoard() {
return board;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public String boardToString() {
StringBuilder sb = new StringBuilder();
for (int x = 0; x < board.length; x++) {
StringJoiner row = new StringJoiner(" ");
for (int y = 0; y < board[x].length; y++) {
row.add(board[x][y] ? "1" : "0");
}
sb.append(row);
}
return sb.toString();
}
private void click(int centerX, int centerY) {
toggle(centerX, centerY);
toggle(centerX, centerY - 1);
toggle(centerX, centerY + 1);
toggle(centerX - 1, centerY);
toggle(centerX + 1, centerY);
}
private void toggle(int x, int y) {
if (x < 0 || y < 0 || x >= board.length || y >= board[x].length) {
return;
}
board[x][y] = !board[x][y];
}
}
}
Algorithm
If possible, I would also be interested in pure-mathematical arguments that solve or prove this without writing code that solves it by trying out.
The "Lights Out" problem can be simplified by observing that the moves are commutative, i.e. if you flip the plus-shapes centred on a certain set of cells, then it doesn't matter which order you flip them in. So an actual ordered path through a graph is not needed. We can also observe that each move is self-inverse, so no solution requires making the same move more than once, and if a set of moves m is a solution to a position p, then m also produces the position p starting from an empty board.
Here's a short solution in Python based on this observation: I've solved it for the goal of all 0s, i.e. the "lights" are "out", but it is trivial to change it to solve for the goal of all 1s.
The constant list masks represents which cells should be flipped for each of the 9 possible moves.
The bitcount function is used to measure how many moves a solution takes, given a bitmask representing a subset of the 9 possible moves.
The position function computes the board position after a set of moves is made, using the exclusive-or operation to accumulate the results of multiple flips.
The positions dictionary maps each reachable board position to a list of move-sets which produce it starting from an empty board. It turns out that all positions are reachable by exactly one set of moves, but if this is not known in advance then a dictionary of lists gives a more general solution.
The max(..., min(...)) part finds the position maximising the minimum number of moves needed to solve it, as required.
masks = [
int('110100000', 2), int('111010000', 2), int('011001000', 2),
int('100110100', 2), int('010111010', 2), int('001011001', 2),
int('000100110', 2), int('000010111', 2), int('000001011', 2),
]
def bitcount(m):
c = 0
while m:
c += (m & 1)
m >>= 1
return c
def position(m):
r = 0
for i in range(9):
if (1 << i) & m:
r ^= masks[i]
return r
from collections import defaultdict
positions = defaultdict(list)
for m in range(2**9):
p = position(m)
positions[p].append(m)
solution = max(positions, key=lambda p: min(map(bitcount, positions[p])))
print('board:', bin(solution))
print('moves:', ', '.join(map(bin, positions[solution])))
Output:
board: 0b101010101
moves: 0b111111111
That is, the "worst initial position" is an X shape (all four corners plus the centre cell are 1s), and the solution is to perform all 9 moves.
I am proposing an iterative solution to solve this (and related problems) based on graph theory.
Shortest-Path-Problem (SSP)
The problem can be reformulated as shortest-path-problem and, by that, be solved with any standard SPP algorithm, for example Dijkstr's algorithm.
For that, we will interpret all possible game boards as vertices and the action of clicking cells as edges of a graph.
For example
0 1 0
1 1 0
0 0 0
will be a vertex in the graph with 9 outgoing edges in total (one for each cell to click at). So we will for example have an edge
0 1 0 0 0 0
1 1 0 --> 0 0 1
0 0 0 0 1 0
with cost 1. All edge costs will be 1, indicating counting turns.
Given an initial board, like above, we formulate the SPP as the task of finding the shortest path in this graph from the vertex representing the initial board to the vertex representing the solved state
1 1 1
1 1 1
1 1 1
By using standard algorithms for solving SSP we receive the optimal path and its total cost. The path is the sequence of game states and the total cost is the amount of turns needed for that.
*-1 SPP
However, you are not only interested in solving given initial boards but also in finding the worst initial board and its optimal amount of turns.
This can be reformulated as a variant of the SPP family, namely trying to find the longest shortest path to the solved state. This is, among all shortest paths in the graph that end in the solved state, the path that maximizes the total cost.
This can be computed efficiently by a *-1 (many-to-one) SPP. That is, computing all shortest paths from any vertex to a single destination, which will be the solved state. And from those picking the path which has the greatest total cost.
Dijkstra's algorithm can compute that easily by executing the algorithm fully on a reversed graph (all edges reverse their direction) with the solved state as source, until it settled the whole graph (removing its stopping criteria).
Note that in your particular case graph reversal is not needed, as the graph in your game is bidirectional (any turn can be undone by executing it again).
Solution
Applying the above theory yields a pseudo-code looking like
Graph graph = generateGraph(); // all possible game states and turns
int[][] solvedState = [[1, 1, 1], [1, 1, 1], [1, 1, 1]];
List<Path> allShortestPaths = Dijkstra.shortestPathFromSourceToAllNodes(solvedState);
Path longestShortestPath = Collections.max(allPaths);
Some time ago I created a Java library for solving shortest path problems, Maglev. Using that library, the full code is:
import de.zabuza.maglev.external.algorithms.Path;
import de.zabuza.maglev.external.algorithms.ShortestPathComputationBuilder;
import de.zabuza.maglev.external.graph.Graph;
import de.zabuza.maglev.external.graph.simple.SimpleEdge;
import de.zabuza.maglev.external.graph.simple.SimpleGraph;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
import java.util.StringJoiner;
public class GameTest {
public static void main(String[] args) {
Graph<GameState, SimpleEdge<GameState>> graph = generateGraph();
var algo = new ShortestPathComputationBuilder<>(graph).resetOrdinaryDijkstra()
.build();
GameState solvedState =
new GameState(new boolean[][] { { true, true, true }, { true, true, true }, { true, true, true } });
var pathTree = algo.shortestPathReachable(solvedState);
var longestShortestPath = pathTree.getLeaves()
.stream()
.map(pathTree::getPathTo)
.map(Optional::orElseThrow)
.max(Comparator.comparing(Path::getTotalCost))
.orElseThrow();
System.out.println("The longest shortest path has cost: " + longestShortestPath.getTotalCost());
System.out.println("The states are:");
System.out.println(longestShortestPath.iterator().next().getEdge().getSource());
for (var edgeCost : longestShortestPath) {
System.out.println("------------");
System.out.println(edgeCost.getEdge().getDestination());
}
}
private static Graph<GameState, SimpleEdge<GameState>> generateGraph() {
SimpleGraph<GameState, SimpleEdge<GameState>> graph = new SimpleGraph<>();
generateNodes(graph);
generateEdges(graph);
return graph;
}
private static void generateNodes(Graph<GameState, SimpleEdge<GameState>> graph) {
for (int i = 0; i < 1 << 9; i++) {
String boardString = String.format("%09d", Integer.parseInt(Integer.toBinaryString(i)));
graph.addNode(GameState.of(boardString, 3, 3));
}
}
private static void generateEdges(Graph<GameState, SimpleEdge<GameState>> graph) {
for (GameState source : graph.getNodes()) {
// Click on each field
boolean[][] board = source.getBoard();
for (int x = 0; x < board.length; x++) {
for (int y = 0; y < board[x].length; y++) {
GameState destination = new GameState(board);
destination.click(x, y);
graph.addEdge(new SimpleEdge<>(source, destination, 1));
}
}
}
}
private static class GameState {
public static GameState of(String boardString, int rows, int columns) {
boolean[][] board = new boolean[rows][columns];
int i = 0;
for (int x = 0; x < rows; x++) {
for (int y = 0; y < columns; y++) {
board[x][y] = boardString.charAt(i) == '1';
i++;
}
}
return new GameState(board);
}
private final boolean[][] board;
private GameState(boolean[][] board) {
this.board = new boolean[board.length][];
for (int x = 0; x < board.length; x++) {
this.board[x] = new boolean[board[x].length];
for (int y = 0; y < board[x].length; y++) {
this.board[x][y] = board[x][y];
}
}
}
public boolean[][] getBoard() {
return board;
}
#Override
public String toString() {
StringJoiner rowJoiner = new StringJoiner("\n");
for (int x = 0; x < board.length; x++) {
StringJoiner row = new StringJoiner(" ");
for (int y = 0; y < board[x].length; y++) {
row.add(board[x][y] ? "1" : "0");
}
rowJoiner.add(row.toString());
}
return rowJoiner.toString();
}
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final GameState gameState = (GameState) o;
return Arrays.deepEquals(board, gameState.board);
}
#Override
public int hashCode() {
return Arrays.deepHashCode(board);
}
private void click(int x, int y) {
toggle(x, y);
toggle(x, y - 1);
toggle(x, y + 1);
toggle(x - 1, y);
toggle(x + 1, y);
}
private void toggle(int x, int y) {
if (x < 0 || y < 0 || x >= board.length || y >= board[x].length) {
return;
}
board[x][y] = !board[x][y];
}
}
}
Which yields the following solution to your problem:
The longest shortest path has cost: 9.0
The states are:
1 1 1
1 1 1
1 1 1
------------
1 0 1
0 0 0
1 0 1
------------
1 0 1
1 0 0
0 1 1
------------
1 1 0
1 0 1
0 1 1
------------
1 1 0
1 0 0
0 0 0
------------
1 1 0
1 1 0
1 1 1
------------
0 0 1
1 0 0
1 1 1
------------
1 0 1
0 1 0
0 1 1
------------
0 1 1
1 1 0
0 1 1
------------
0 1 0
1 0 1
0 1 0
So the worst initial game state is
0 1 0
1 0 1
0 1 0
and, if played optimally, it needs 9 turns to solve the game.
Some trivia, the game has 512 states in total (2^9) and 4608 possible moves.
Treat the puzzle as a graph per Zabuzard's answer, then perform breadth-first search starting from the solved node. The last node you reach is among the set having the longest-shortest path to the solution.
If possible, I would also be interested in pure-mathematical arguments that solve or prove this without writing code that solves it by trying out.
I am proposing a solution purely based on linear algebra.
Board as matrix
The game can be interpreted as set of linear equations which can be solved using standard linear equation solving techniques.
For that, a game board is interpreted as matrix .
In total, there are 9 possible actions (one for clicking each cell of the board). We encode which cells have to be flipped per action in 9 corresponding matrices:
where is the action-matrix corresponding to a click on cell in row i and column j.
Actions are commutative and self-inverse
Since entries are in , applying an action to a given board is as simple as adding the corresponding action-matrix to the board-matrix. For example:
This means that applying a set of actions is nothing else than some matrix additions. Matrix additions are commutative. This means that the order in which they are applied does not matter:
Moreover, any action-matrix is self-inverse on addition. Applying it again undoes the action, i.e.
This follows that, for any initial game board, we only have to apply each action at most once and the order in which we do that does not matter.
Linear equation system
This leads to the equation:
With the initial game board matrix L, coefficients which are 1 if the action should be applied, otherwise 0; and 1 being the all-ones matrix indicating that the game is won.
The equation can be simplified by moving L to the other side:
where L* is L but with all cells flipped.
Finally, this equation can be rewritten as standard linear system of equations Ax = b which can then be solved easily:
Since this matrix has maximal rank and a non-zero determinant , the game on a 3x3 board is always solvable and a solution is given by simply solving the linear equation system or by applying Cramer's rule.
Worst initial board
It also follows that the worst initial board is a matrix L that maximizes the coefficients being used, ideally all 9.
Turns out
0 1 0
1 0 1
0 1 0
is such an initial board which needs all 9 coeeficients to be set for a solution. I.e. solving the system
yields exactly one solution, namely for all i, j.
This can also be obtained from the opposite direction by setting all coefficients to 1 and solving for L instead:
which yields
0 1 0
1 0 1
0 1 0
for L again.

Algorithm not showing right output

The Question was:
You are given a binary matrix (i.e. each element of matrix is either 0 or 1) of size n × n. You want to re-arrange 1's in such a way that they form a rectangular region. Note that the rectangular region should be made of only 1's, and all the 1's of the entire matrix should be in this rectangular region.
For achieving rectangular region, you can swap any two elements of the matrix. Please find out the minimum number of swaps needed. If it is not possible to re-arrange 1's in the desired way, please print -1.
Input
First line of the input contains a single integer T denoting number of test cases.
Description of T test cases follows.
First line of each test case will contain a single integer n denoting dimension of matrix.
Each of next n lines will contain n space separated integers denoting the ith row of the matrix.
Output
For each test case, print a single line containing a single integer denoting minimum number of swaps needed or -1 depending on the situation.
Example
Input:
2
2
0 1
1 0
2
1 1
1 0
Output:
1
-1
Explanation
Example case 1. You can swap 1 of second row first column with 0 of first row first column.
After the swap, matrix will look as follows.
1 1
0 0
Here all the 1's form a rectangular region of dimension 1 × 2. In this case, 1 swap will be needed.
Note that you can also swap 1 at first row second column with 0 at second row second column too.
Matrix after this swap will be following.
0 0
1 1
So you need 1 swap in this case too.
So overall, you need 1 swap.
Example case 2. There is no way to create a rectangular region containing 3 1's in a matrix of dimension 2 × 2, hence answer is -1.
My Algorithm [Edit]
First i am Taking Number of Cases from user
Then the order of matrix [will be of nxn order].
So logic is that if matrix is 1x1 then it will simply print 0
else while taking input from user [that will be only 1 or 0] i am counting 1's because the logic i develop that when in a matrix of odd order the 1's will be even then it cannot be arranged in rectangular form.and for even order of matrix if 1's are odd , not arrange able .
Next i am traversing each index if i find one then i move to next element else i try to find 1 in the same colomn if dont find than i am breaking loop showing -1 that it is not arrange able in rectangular form
Than after arranging a row i check the next row whether it is already arranged or not if it is than i break everything and moves to next case
n rectangular form
My Solution
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
static long startTime;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int numberOfOnes = 0;
int T = scanner.nextInt();
for (int t = 1; t <= T; t++) {
int n = scanner.nextInt();
int loopCounter, swapCounter = 0;
boolean rowContainsZero = false;
int array[][] = new int[n][n];
boolean reject = true;
//Worst and the most simpler conditions
if (n == 1) {
System.out.print("0");
exitingSystem();
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
array[i][j] = scanner.nextInt();
if (array[i][j] == 1) {
numberOfOnes++;
}
}
}
if (n % 2 == 0 && numberOfOnes % 2 != 0) {
System.out.println("-1");
if (t == T) {
exitingSystem();
}
continue;
} else if (n % 2 != 0 && numberOfOnes % 2 == 0) {
System.out.println("-1");
if (t == T) {
exitingSystem();
}
continue;
}
// System.out.println("Here i am");
//From here swaping processes will take the place
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (array[i][j] == 1) {
continue;
} else if (array[i][j] == 0) {
loopCounter = i;
reject = true;
while (loopCounter < n) {
if (array[loopCounter][j] == 1) {
int temp = array[loopCounter][j];
array[loopCounter][j] = array[i][j];
array[i][j] = temp;
reject = false;
swapCounter += 1;
break;
}
loopCounter++;
}
if (rowContainsZero) {
System.out.println("" + swapCounter);
break;
}
if (reject == true) {
System.out.println("-1");
break;
} else {
for (int m = i + 1; m < n; m++) {
for (int k = 0; k < n; k++) {
if (array[m][k] == 0) {
rowContainsZero = true;
} else {
rowContainsZero = false;
break;
}
}
}
}
} else {
System.out.println("0's and 1's were Expected :(");
exitingSystem();
}
}
if (reject == true) {
break;
}
}
}
}
public static void exitingSystem() {
System.exit(0);
}
}
BUT THE CODECHEF COMPUTER SAYING WRONG ANSWER + They allowed to take input from keyboard too
I think your algorithm isn't fully correct.
I think the following is a counter-example for your step 4 / odd order (n=3) and even number of ones (numberOfOnes=4):
1 1 0
1 1 0
0 0 0
This should give 0.
Similar for n=4 and numberOfOnes=3:
1 1 1 0
0 0 0 0
0 0 0 0
0 0 0 0
This should give 0 as well.
I haven't yet deeply analyzed your steps 5 and 6.
Here are some more examples:
1 1 1 0
1 1 0 0
1 1 1 0
1 1 0 0
This should give -1, as from 10 ones you can only form rectangles of the form 2*5 or 1*10, which both don't fit into the 4*4 frame.
1 1 1 0
1 1 0 0
1 1 1 0
1 0 0 0
This should give 1, as by moving the lower-left 1 two palces up and right, you get a 3*3 rectangle.
This is not the way you are trying to solve problem. Suppose you have
0 0 1
0 1 1
0 0 1
This is a perfect example of solveable matrix but you can't simply use random swap and then acquire result. You need to use A* search algorithm with manhatten distance.
Make a priority queue
Define manhatten distance.
Create a function which creates succesors of each board. Like if i have above board then it will give you a collection of boards back:
0 0 1
0 1 1 ==> colection
0 0 1
0 1 1
0 0 1
0 0 1
0 0 1
0 0 1
0 1 1
0 1 0
0 1 1
0 0 1
0 0 1
0 1 1
0 1 0
Description of A:*
an initial lis to store visited boar so that you don't visit them again.
i will call MinPriority queue a pq
`insert the initial_board in pq
while(!pq.isEmpty() && !foundGoal(pq.min)) //You find goal when your
manhatten distance is 0.
board = pq.delMin(); //you have to override the distance method in
priority queue so it will return you that board whoms manhatten
distance is smallest.
for(boards b :board.getSuccesors(); // give you collection of boards.
if(notvisited(b,vistiedList)) // so that you don't come in same state again and
again.
pq.insert(b);
visitedList.add(b);`
In first year i had to solve 8-puzzle and you can solve this way however you can also use hamming distance but that's not efficient and here is 8-puzzle code(with A* implementation).

How to use memoization in counting a large number of matrices

I have been given a program, which requires me to count the number of previous states for a matrix.
The given matrix is a boolean matrix. I will use 1 for true and 0 for false to explain the program.
The next state of a cell in a matrix is 1 if, considering these four cells:
the cell itself
the cell right to it
the cell below it
the cell below it, and to its right,
there is only one 1 in all these 4 cells, i.e., there are exactly 3 0s and exactly 1 1 in these 4 cells.
If the given matrix (M) is :
1 1 0 0
0 0 0 1
0 0 1 0
Then for the first cell (M[0][0]), the four cells to be considered are M[0][0], M[0][1], M[1][0] and M[1][1]. So, the next state of the first cell is 0, because we have 2 1 in these 4 cells.
For the second cell (M[0][1]), the four cells to be considered are M[0][1], M[0][2], M[1][1], M[1][2]. So the next state for this cell is 1 because there is only 1 1 in these four cells.
Going this way, the next state for this matrix(M) would be the matrix (N):
0 1 1
0 1 0
The next state will, obviously, be 1 row and 1 column less than the previous state. Thus, a given state of the matrix can have many previous states, for example, besides matrix M, the given matrix :
1 0 1 0
1 0 0 0
1 1 0 0
will also have the next state N.
I have to count the number of previous states that a given matrix has.
I have written the following code :
public class Answer2 {
static boolean[][] main_array,answer_array; // answer_array is the 2D array given to me. main_array is the 2D array which I recurse through, and then find its solution to compare with answer_array.
static int c; // counter
static int answer_array_height,answer_array_width; // matrix height and matrix width
public static int answer(boolean[][] boolean_array)
{
answer_array = boolean_array;
main_array = new boolean[answer_array.length+1][answer_array[0].length+1];
c=0;
answer_array_height = answer_array.length;
answer_array_width = answer_array[0].length;
recurse(1,1);
main_array[0][0] = true;
recurse(1,1);
return c;
}
public static String pad(String s, int l){ //Add 0's to the beginning of the string till its length equals l
for(int i=s.length(); i<l; i++)
s='0'+s;
return s;
}
public static void recurse(int w, int h){
if(w==answer_array_width+1 && h==answer_array_height+1){
c++;
return;
}
//System.out.println(java.util.Arrays.deepToString(main_array).replace("],","],\n").replace("true","1").replace("false","0"));
if(h==answer_array_height+1 || h>=w){//Add column
int x = 0;
for(int i=0; i<h; i++) x+=(int)Math.pow(2,i); //This will give me the integer representation of max value(whose binary representation will be used to put values in the matrix) to handle.
for(int i=0; i<=x; i++){
String str = pad(Integer.toBinaryString(i),h);
for(int j=0; j<h; j++){
main_array[j][w]= str.charAt(j)=='1'; //set main_array[j][w] true wherever the binary representation of i has 1. This recurses through all the combinations.
}
if(check(w+1,h,false)){
recurse(w+1, h);
}else{
for(int j=0; j<h; j++){
main_array[j][w]=false;
}
}
}
}else{//Add row
int x = 0;
for(int i=0; i<w; i++) x+=(int)Math.pow(2,i);
for(int i=0; i<=x; i++){
String str = pad(Integer.toBinaryString(i),w);
for(int j=0; j<w; j++){
main_array[h][j]= str.charAt(j)=='1';
}
if(check(w,h+1,true)){
recurse(w, h+1);
}else{
for(int j=0; j<w; j++){
main_array[h][j]=false;
}
}
}
}
}
// w is the effective width, h is the effective height, height_was_increased is true if height was increased, false if width was increased.
//height_was_increased helps to shorten the time used for comparison as the matrix was correct before the width or height was increased. So it just needs to check the increased portion.
public static boolean check(int w, int h, boolean height_was_increased){
if(height_was_increased){
for(int j=0; j<w-1; j++){
//I know this part is complex. It just finds out the answer of the four cells to be considered and matches it with the given matrix.
if(answer_array[h-2][j] != (main_array[h-2][j]^main_array[h-2+1][j]^main_array[h-2][j+1]^main_array[h-2+1][j+1] && !(main_array[h-2][j] && main_array[h-2+1][j]) && !(main_array[h-2][j+1] && main_array[h-2+1][j+1]))) return false;
}
}else{
for(int i=0; i<h-1; i++){
if(answer_array[i][w-2] != (main_array[i][w-2]^main_array[i+1][w-2]^main_array[i][w-2+1]^main_array[i+1][w-2+1] && !(main_array[i] [w-2] && main_array[i+1][w-2]) && !(main_array[i][w-2+1] && main_array[i+1][w-2+1]))) return false;
}
}
return true;
}
}
What it basically does, is that it begins with an empty matrix (of the appropriate size for its next state that gives the matrix asked for) and starts from the top left corner, increasing the effective width and height alternately by 1, and checking if the next state of the matrix till now corresponds to the given state. If not, it skips the rest of the matrix. Then, if a matrix whose next state is the same as the given state is found, it increases the counter by 1.
This code works for small matrices (no. of cells <40), but it takes a lot of time for large matrices. The maximum width of the matrix can be 50 and the maximum height can be 9. So this code doesn't quite work for that purpose.
I know that I have to use memoization here (doing c++ thousands of times is just not right!) But I can't imagine how to implement it. I have previously written programs using dynamic programming, but have no idea where it would be used here. Any help would be appreciated.
There are lot of possible matrices that produce given next state. If next state matrix N is given and initial matrix M is partially filled, for example elements m[x][y+1], m[x+1][y], and m[x+1][y+1]
are filled, than possibilities for element m[x][y] are checked with value s = m[x][y+1] + m[x+1][y] + m[x+1][y+1], in a way:
if n[x][y] == 1:
if s == 0 than m[x][y] = 1
if s == 1 than m[x][y] = 0
if s > 1 than m[x][y] can't be filled
if n[x][y] == 0:
if s == 0 than m[x][y] = 0
if s == 1 than m[x][y] = 1
if s > 1 than m[x][y] = 0 or 1
It looks like values 1 in N 'filter' combinations and values 0 in N 'multiply' them.
Since height is bounded by smaller value I suggest approach first to fill last column with possible
values, than pass columns backward, fill last column element and than by upper check fill element by element.
Python implementation:
import numpy
from itertools import product
num_results = 0
def fill_xy(m, s, x, y):
if y < 0:
fill_x_last(m, s, x-1)
return
_sum = s[x+1, y] + s[x+1, y+1] + s[x, y+1]
if m[x, y] == 1:
if _sum == 0:
s[x, y] = 1
elif _sum == 1:
s[x, y] = 0
else:
return
else:
if _sum == 0:
s[x, y] = 0
elif _sum == 1:
s[x, y] = 1
else:
s[x, y] = 0
fill_xy(m, s, x, y-1)
s[x, y] = 1
fill_xy(m, s, x, y-1)
def fill_x_last(m, s, x):
global num_results
if x < 0:
print s
num_results += 1
else:
s[x, s.shape[1]-1] = 0
fill_xy(m, s, x, s.shape[1]-2)
s[x, s.shape[1]-1] = 1
fill_xy(m, s, x, s.shape[1]-2)
def solve(m):
global num_results
height = m.shape[1]+1
s = numpy.zeros((m.shape[0]+1, height), dtype=numpy.uint8)
for p in product((0, 1), repeat=height):
s[-1, :] = p
fill_x_last(m, s, s.shape[0]-2)
print num_results
solve(numpy.array([[0, 1, 1], [0, 1, 0]], dtype=numpy.uint8))

Finding smallest neighbour in a 2D array

I have some code that is supposed to find the smallest of the 8 neighboring cells in a 2D array. When this code runs, the smallest is then moved to, and the code run again in a loop. However when it is run the code ends up giving a stack overflow error as it keeps jumping between two points. This seems to be a logical paradox as if Y < X then X !< Y. So it think it is my code at fault, rather than my logic. Here's my code:
private Point findLowestWeight(Point current) {
float lowest = Float.MAX_VALUE;
Point ret = new Point(-1, -1);
LinkedList<Point> pointList = new LinkedList<Point>();
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (!(i == 0 && j == 0)) {
if ((current.x + i >= 0 && current.x + i <= imageX - 2)
&& (current.y + j >= 0 && current.y + j <= imageY - 2)) {
pointList.add(new Point(current.x + i, current.y + j));
}
}
}
}
for (Point p : pointList){
if (map[p.x][p.y] < lowest){
lowest = map[p.x][p.y];
ret = p;
}
}
return ret;
}
You need a stopping case.
find the smallest of the 8 neighboring cells in a 2D array. When this code runs, the smallest is then moved to, and the code run again in a loop
is a fine way to start but says nothing about stopping.
Do you care about the value of the current cell? If so you need to check 9 not 8. If you simply want to move down hill then you need to check where you've been or any flat multi-cell valley will put you into an infinite loop. Consider only moving if moving down.
If you truly don't care where you are then even a single cell valley will put you into an infinite loop as you bounce in and out of it. In which case you'd need some other stopping condition. Consider stopping after imageX * imageY iterations.
Do you move even if the smallest neighbour is greater than the value in the center?
Example:
2 2 2 2
2 0 1 2
2 2 2 2
You start with center cell 0. The smallest neighbour is 1. If you move to 1, the smallest neighbour is 0. You can continue endless.
Probably you should not move, if the smallest neighbour is greater than the current cell.

Java Netbeans 6.5 Mastermind Calculating White Pegs

For my Mastermind Game I am using 6 numbers instead of 6 colours. Also instead of showing black and white pegs, just 2 sentences are outputted. One reads:
"The number of correct digits in the right position is __ "(black pegs/bothRight)
"The number of correct digits in the wrong position is __ "(white pegs/numberRight)
For the 4 digit guesses that are submitted, I am using an array called guessArr, which accepts 4 values from 4 input boxes.
guess0 = Integer.parseInt(firstInput.getText());
guess1 = Integer.parseInt(secondInput.getText());
guess2 = Integer.parseInt(thirdInput.getText());
guess3 = Integer.parseInt(fourthInput.getText());
//New array to arrange guesses
int[] guessArr = new int[] {guess0,guess1,guess2,guess3};
For the answer generated by the computer,
//Create a 4 digit code made of random numbers between 1 and 6
answerArr[0]=(int)(Math.random()*6+1);
answerArr[1]=(int)(Math.random()*6+1);
answerArr[2]=(int)(Math.random()*6+1);
answerArr[3]=(int)(Math.random()*6+1);
Finding the amount of black pegs is easy:
//Calculate number of correct digits in correct position
for (int i = 0; i < 4; ++i)
{
if (answerArr[i] == guessArr[i])
{
used[i] = true;
bothRight++;
}
}
EDIT
I've Solved It!
// Calculate number of correct numbers in wrong position
//Declare variables for what digits are in the answer
Integer digit1 = 0, digit2 = 0, digit3 = 0, digit4 = 0, digit5 = 0 , digit6 = 0;
//Find what the answer digits are
for (int k = 0; k < answerArr.length; ++k){
if (answerArr [k] == 1)
{
digit1++;
}
if (answerArr [k] == 2)
{
digit2++;
}
if (answerArr [k] == 3)
{
digit3++;
}
if (answerArr [k] == 4)
{
digit4++;
}
if (answerArr [k] == 5)
{
digit5++;
}
if (answerArr [k] == 6)
{
digit6++;
}
}
//Declare variables for what digits are in the answer
Integer gDigit1 = 0, gDigit2 = 0, gDigit3 = 0, gDigit4 = 0, gDigit5 = 0 , gDigit6 = 0;
//Find the guess numbers submitted
for (int p = 0; p < guessArr.length; ++p){
if (guessArr [p] == 1)
{
gDigit1++;
}
else if (guessArr [p] == 2)
{
gDigit2++;
}
else if (guessArr [p] == 3)
{
gDigit3++;
}
else if (guessArr [p] == 4)
{
gDigit4++;
}
else if (guessArr [p] == 5)
{
gDigit5++;
}
else if (guessArr [p] == 6)
{
gDigit6++;
if (gDigit6 == 0)
{
gDigit6++;
}
}
//Find the value of correct numbers submitted in the guess
Integer correctNumbers = Math.min (digit1, gDigit1) + Math.min (digit2, gDigit2) + Math.min (digit3, gDigit3) +
Math.min (digit4, gDigit4) + Math.min (digit5, gDigit5) + Math.min (digit6, gDigit6);
//Calculate value of numberRight
numberRight = (correctNumbers - bothRight);
}
Any help would be greatly appreciated. :D Thanks.
First, I'll say up front, I'm not going to give you any code since this is either a learning exercise, so you can learn the language, or else this is a class problem.
So, lets think about this logically... One way you can you can solve this is by counting the number of a type of colors.
As an example, suppose the player guessed 2 blues, and 2 greens, and the answer has 1 blue, 1 red, and two greens.
The player guessed 3 of the right colors, so you would give them 3 white pegs UNLESS they got some in the right spot. Now, suppose that they got one of those blues in the right spot, that means they have 1 black peg, which replaces a white peg. So, the grand total is 2 white pegs, and 1 black peg.
So, to find the number of "Correct Colors" you should check each color (good chance for a loop?) and compare the number of each color that the player guessed, to the number of each color that the solution has.
Put another way, you don't want to compare the guess to the answer. You want to compare the count for each color on the guess, to the count of each color on the solution.
Then, you get "White pegs" by this pesudo-code:
int whitePegs=correctColors-blackPegs;
Edit 1: Comparing answers one color at a time
If you're going to hold the count for each color, then you're going to want to use two arrays, one for the guess, and one for the solution. Each element in the array will hold the count for the color, like this:
r=red, o=orange, y=yellow, etc.
R O Y G B
Guess: [0][2][1][1][0] (Total is 4, for 4 pegs
Actual: [1][1][2][0][0] (Total is 4) for 4 pegs
Matches:[0][1][1][0][0] (Total is 2) This is "correctColors" from above

Categories