Issues with logic in a nested for loop - java

Closely related to Java programming - nested for loops for minesweeper game, my Minesweeper program is designed to loop through cells, check each adjacent cell, perform a logic test to check if it's a Mine, and then jump to the next one. However, when I run it, it somehow becomes an infinite loop. I've tried changing variables, reversing signs (< becomes > and + becomes -), and googling other solutions, but I can't find anything.
Printouts are for debugging, gameboard is set to [10][10],
public static void assignNumbers(int[][] gameBoard)
{
for(int r = 0; r <= (gameBoard.length - 1); r++){ //row
for(int c = 0; c <= (gameBoard[0].length - 1); r++){ //column
System.out.print("New Cell ");
for(int vR = r+1; vR > r-2; vR --){ //vR is visiting Row
for(int vC = c+1; vC > c-2; vC --){ //vC is visiting Column
System.out.print("new item ");
if (isValid(vR, vC, gameBoard)){
System.out.print("isMine? ");
if (isMine(vR, vC, gameBoard)){
gameBoard[r][c] += 1;
System.out.print(" MINE ");
}
else {
System.out.print(" NO ");
}
}
}
}
System.out.println();
}
}
}
public static boolean isMine(int r, int c, int[][] gameBoard){
if(gameBoard[r][c] != 100){
return false;
}
else{
return true;
}
}
public static boolean isValid(int r, int c, int[][] gameBoard)
{
// Returns true if row number and column number
// is in range
return ((r >= 0) && (r < SIDE)) && ((c >= 0) && (c < SIDE)) && !isMine(r, c, gameBoard);
}
When I try to run it, I get an infinite printout saying :
"New Cell" followed by 9 "new items". This should only print out 100 times (once for each cell), however it doesn't stop after 100. I assume it's a logic error in one of the for loops, but I can't find it for the life of me. Any help is appreciated, and I'll do my best to answer any questions.
EDIT: punctuation

Try to replace r++ with c++
for(int c = 0; c <= (gameBoard[0].length - 1); c++){ //column

Related

Recursive method to replace all occurrences of a value in a 2D array

I have created a recursive method that replaces all occurrences of an element in a two dimensional double array. The issue is that I cannot seem to get this working without encountering a stack overflow error. Could someone please look at my code below and show me how to fix this? I have tried setting this up several times over the past few days. Thank you. Note that my arrays are 2 x 3, so the first if means that if you are at column 1 row 2, you are at the end of the array, and in that case you are done searching.
private static int replaceAll(double number, double replacementTerm) {
int i = 0;
int j = 0;
double searchFor = number;
double replace = replacementTerm;
if (i == 1 && j == 2) {
System.out.println("Search complete!");
}
if (twoDimArray2[i][j] == searchFor) {
System.out.println("Replaced An Element!");
twoDimArray2[i][j] = replace;
System.out.println(twoDimArray2[i][j]);
j++;
return replaceAll(searchFor, replace);
}
if (j == twoDimArray2.length) {
i++;
return replaceAll(searchFor, replace);
} else {
j++;
return replaceAll(searchFor, replace);
}
}
i and j should be method parameters instead of local variables so changes to their values can be tracked. Try to move right and down recursively if it does not exceed the bounds of the array. Note that this is much less efficient that iteration with two layers of for loops, as it will check multiple positions in the array more than once; to mitigate this, one can use a visited array to store all positions previous visited so they will not be checked again. See the below code in action here.
private static void replaceAll(double number, double replacementTerm, int i, int j) {
double searchFor = number;
double replace = replacementTerm;
if (twoDimArray2[i][j] == searchFor) {
System.out.println("Replaced An Element!");
twoDimArray2[i][j] = replace;
System.out.println(twoDimArray2[i][j]);
}
if (i == twoDimArray2.length - 1 && j == twoDimArray2[0].length - 1) {
System.out.println("Reached the end!");
return;
}
if (i + 1 < twoDimArray2.length) {
replaceAll(number, replacementTerm, i + 1, j);
}
if (j + 1 < twoDimArray2[0].length) {
replaceAll(number, replacementTerm, i, j + 1);
}
}

An efficient way to get and store the shortest paths

When I say efficient I mean code that isn't cpu intensive.
The Problem:
I have a field of blocks. Like in the following image:
Every single one of these blocks represents an instance of a self-made Block class. This block class has a List<Block> neighBours, where the neighbours of the block are stored. So every single block in the image knows which blocks are next to it.
What I want to do is to pick any block from this image, and compute how many "steps" away this block is. For example if I pick the block in the top left, I want to have a Map<Block, Integer> representing how many "steps" away each block is from the picked block. Like this:
Now before you say "Just store it's position X and Y in the block class and calculate the difference X + difference Y", that wouldn't work because the field can have gaps(represented by red color) between them like the following image:
And as you might notice, the block next to the gap that was first 4 steps away, is now 6 steps away. Thus the best way(I presume) to get how many steps away the other blocks are is by using a recursive algorith that makes use of the neighbour info. I couldn't make an efficient one myself and I was hoping someone might know something that works well.
Several problems I came across are the fact that because all blocks know their neighbours, the recursive algorithm would go indefinately back and forth between the first and second block. Or the fact that when using the algorithm on a 11x11 field, there were 3284 method calls, which seems waaay too high for an 11x11 field.
Question:
So the question I have is: What is an efficient way, using the knowledge of what neighbours each block has, to get how many steps away each block is.
Code:
This is the current code that I have incase anyone wants to see it.
public class Block
{
List<Block> neighBours;
public Block(List<Block> neighBours)
{
this.neighBours = neighBours;
}
public Map<Block, Integer> getStepsAway()
{
Map<Block, Integer> path = new HashMap<Block, Integer>();
getPaths(path, 0, 100);
return path;
}
public void getPaths(Map<Block, Integer> path, int pathNumber, int maxPathNumber)
{
if(pathNumber <= maxPathNumber)
{
for(Block block : neighBours)
{
Integer thePathNumber = path.get(block);
if(thePathNumber != null)
{
if(pathNumber < thePathNumber)
{
path.put(block, pathNumber);
block.getPaths(path, pathNumber + 1, maxPathNumber);
}
}
else
{
path.put(block, pathNumber);
block.getPaths(path, pathNumber + 1, maxPathNumber);
}
}
}
}
}
Recursive algorithms are doomed to fail on a large grid. Java is not designed for deep recursions and can only withstand a few thousands recursive calls before failing with a StackOverflowException. Only iterative solutions are a reasonible approach for large pathfinding problems in Java.
Of course you can always use a classic pathfinding algorithm such as A*, but you would have to apply it for each cell, which would be extremely expensive.
Indeed, your problem is a bit particular in the sense you want to calculate the minimum distance to all cells and not only just one. Therefore, you can do it in a more clever way.
One property of your problem is that given A and B, if the minimal path from A to B contains C then this path is also minimal from A to C and from C to B. That's what my intuition tells me, but it would need to be proven before implementing my suggestion.
The algorithm I propose is efficient, uses O(n) memory and has O(n^2) runtime complexity (cannot be faster since you need to set this many cells in the array):
start with your first point and set the distance of all its valid neighbours to 1. Doing so, you will record the border, which is all the cells at distance 1 from the first cell.
then, you iterate over the border and take all their neighbours which have not already been assigned a distance and assign them distance 2. All cells of distance 2 become your new border.
iterate until the border is empty
Below is a full working solution. The code may be improved in various ways using more convenience methods for initializing and printing matrices of objects and primitive integers, but you get the idea:
public class Solution {
public enum Cell { FREE, BLOCKED }
// assuming cells is a rectangular array with non-empty columns
public static int[][] distances(Cell[][] cells, ArrayCoordinate startingPoint) {
int[][] distances = new int[cells.length][cells[0].length];
// -1 will mean that the cell is unreachable from the startingPoint
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[0].length; j++) {
distances[i][j] = -1;
}
}
distances[startingPoint.i][startingPoint.j] = 0;
Set<ArrayCoordinate> border = startingPoint.validNeighbours(cells);
for (int currentDistance = 1; !border.isEmpty(); currentDistance++) {
Set<ArrayCoordinate> newBorder = new HashSet<>();
for (ArrayCoordinate coord : border) {
distances[coord.i][coord.j] = currentDistance;
for (ArrayCoordinate neighbour : coord.validNeighbours(cells)) {
if (distances[neighbour.i][neighbour.j] < 0) {
newBorder.add(neighbour);
}
}
}
border = newBorder;
}
return distances;
}
private static class ArrayCoordinate {
public ArrayCoordinate(int i, int j) {
if (i < 0 || j < 0) throw new IllegalArgumentException("Array coordinates must be positive");
this.i = i;
this.j = j;
}
public final int i, j;
public Set<ArrayCoordinate> validNeighbours(Cell[][] cells) {
Set<ArrayCoordinate> neighbours = new HashSet<>();
// inlining for not doing extra work in a loop iterating over (-1, 1) x (-1, 1). If diagonals are allowed
// then switch for using a loop
addIfValid(cells, neighbours, 1, 0);
addIfValid(cells, neighbours, -1, 0);
addIfValid(cells, neighbours, 0, 1);
addIfValid(cells, neighbours, 0, -1);
return neighbours;
}
private void addIfValid(Cell[][] cells, Set<ArrayCoordinate> neighbours, int dx, int dy) {
int x = i + dx, y = j + dy;
if (0 <= x && 0 <= y && x < cells.length && y < cells[0].length && cells[x][y] == Cell.FREE) {
neighbours.add(new ArrayCoordinate(i + dx, j + dy));
}
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ArrayCoordinate point = (ArrayCoordinate) o;
if (i != point.i) return false;
if (j != point.j) return false;
return true;
}
#Override
public int hashCode() {
int result = i;
result = 31 * result + j;
return result;
}
}
public static void main(String[] args) {
int n = 11, m = 5;
Cell[][] cells = new Cell[n][m];
cells[1][1] = Cell.BLOCKED;
cells[1][2] = Cell.BLOCKED;
cells[2][1] = Cell.BLOCKED;
ArrayCoordinate startingPoint = new ArrayCoordinate(5, 2);
System.out.println("Initial matrix:");
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[0].length; j++) {
if (cells[i][j] == null) {
cells[i][j] = Cell.FREE;
}
if (startingPoint.i == i && startingPoint.j == j) {
System.out.print("S ");
} else {
System.out.print(cells[i][j] == Cell.FREE ? ". " : "X ");
}
}
System.out.println();
}
int[][] distances = distances(cells, startingPoint);
System.out.println("\nDistances from starting point:");
for (int i = 0; i < distances.length; i++) {
for (int j = 0; j < distances[0].length; j++) {
System.out.print((distances[i][j] < 0 ? "X" : distances[i][j]) + " ");
}
System.out.println();
}
}
}
Output:
Initial matrix:
. . . . .
. X X . .
. X . . .
. . . . .
. . . . .
. . S . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Distances from starting point:
7 8 7 6 7
6 X X 5 6
5 X 3 4 5
4 3 2 3 4
3 2 1 2 3
2 1 0 1 2
3 2 1 2 3
4 3 2 3 4
5 4 3 4 5
6 5 4 5 6
7 6 5 6 7
Bonus
I almost cried when I saw all this boilerplate in my Java solution, so I wrote a shorter (perhaps slightly less efficient) version in Scala:
object ScalaSolution {
sealed abstract class Cell
object Free extends Cell
object Blocked extends Cell
// assuming cells is a rectangular array with non-empty columns
def distances(cells: Array[Array[Cell]], startingPoint: (Int, Int)) = {
// -1 will mean that the cell is unreachable from the startingPoint
val distances = Array.fill[Int](cells.length, cells(0).length)(-1)
distances(startingPoint._1)(startingPoint._2) = 0
var (currentDistance, border) = (1, validNeighbours(cells, startingPoint))
while (border.nonEmpty) {
border.foreach { case (i, j) => distances(i)(j) = currentDistance }
border = border.flatMap(validNeighbours(cells, _)).filter { case (i, j) => distances(i)(j) < 0 }
currentDistance += 1
}
distances
}
private def validNeighbours(cells: Array[Array[Cell]], startingPoint: (Int, Int)) = {
// inlining for not doing extra work in a for yield iterating over (-1, 1) x (-1, 1). If diagonals are allowed
// then switch for using a for yield
Set(neighbourIfValid(cells, startingPoint, ( 1, 0)),
neighbourIfValid(cells, startingPoint, (-1, 0)),
neighbourIfValid(cells, startingPoint, ( 0, 1)),
neighbourIfValid(cells, startingPoint, ( 0, -1)))
.flatten
}
private def neighbourIfValid(cells: Array[Array[Cell]], origin: (Int, Int), delta: (Int, Int)) = {
val (x, y) = (origin._1 + delta._1, origin._2 + delta._2)
if (0 <= x && 0 <= y && x < cells.length && y < cells(0).length && cells(x)(y) == Free) {
Some(x, y)
} else None
}
def main (args: Array[String]): Unit = {
val (n, m) = (11, 5)
val cells: Array[Array[Cell]] = Array.fill(n, m)(Free)
cells(1)(1) = Blocked
cells(1)(2) = Blocked
cells(2)(1) = Blocked
val startingPoint = (5, 2)
println("Initial matrix:")
printMatrix(cells)((i, j, value) => if ((i, j) == startingPoint) "S" else if (value == Free) "." else "X")
val distancesMatrix = distances(cells, startingPoint)
println("\nDistances from starting point:")
printMatrix(distancesMatrix)((i, j, value) => if (value < 0) "X" else value.toString)
}
private def printMatrix[T](matrix: Array[Array[T]])(formatter: (Int, Int, T) => String) = {
for (i <- 0 until matrix.length) {
for (j <- 0 until matrix(0).length) {
print(formatter(i, j, matrix(i)(j)) + " ")
}
println()
}
}
}
I believe there is a DP (dynamic programming) solution to this problem, looking at this, code below. I realize this is for finding all possible paths to a cell but it can give insight on your condition about 'blanks' or 'walls'
#include <iostream>
using namespace std;
// Returns count of possible paths to reach cell at row number m and column
// number n from the topmost leftmost cell (cell at 1, 1)
int numberOfPaths(int m, int n)
{
// Create a 2D table to store results of subproblems
int count[m][n];
// Count of paths to reach any cell in first column is 1
for (int i = 0; i < m; i++)
count[i][0] = 1;
// Count of paths to reach any cell in first column is 1
for (int j = 0; j < n; j++)
count[0][j] = 1;
// Calculate count of paths for other cells in bottom-up manner using
// the recursive solution
for (int i = 1; i < m; i++)
{
for (int j = 1; j < n; j++)
// By uncommenting the last part the code calculatest he total
// possible paths if the diagonal Movements are allowed
count[i][j] = count[i-1][j] + count[i][j-1]; //+ count[i-1][j-1];
}
return count[m-1][n-1];
}

Java for-loops: How to check for winner in connect 4 program

I am trying to make a connect 4 program in java and I am stuck on the winner check. I know that I could make a very long list of if and else if's but I think loops would work better. I'm open to any other way of solving this problem but on what I've been looking at makes it seem the best. I have an idea of what to do with the rows and columns but I don't even know where to start with the diagonals. This is what I have so far:
edit:
int p1counter = 0;
int p2counter = 0;
int r = 1;//x
int c = 1;//y
for(r = 1; r <= 6; r++)
{
while(c <= 7)
{
if(grid[r][c].equals("_"))
{
c++;
p1counter = 0; p2counter = 0;
}
else if(grid[r][c].equals("1"))//player 1 counter
{
c++;
p1counter++;
}
else if(grid[r][c].equals("2"))//player 2 counter
{
c++;
p2counter++;
}
}
if(p1counter >= 4)
{
JOptionPane.showMessageDialog(null, "Player 1 is the winner!");
done = true;
}
else if(p2counter >= 4)
{
JOptionPane.showMessageDialog(null, "Player 2 is the winner!");
done = true;
}
return done;
}
In similar situations I have done the following:
Create an array of strings; as many strings as there are rows+columns+diagonals
Traverse the grid in the four possible directions (this does not include every possible diagonal since diagonals must be at least 4 long) and enter a corresponding character in the string: for example 0 (empty), 1, 2
Search the string array for 1111 and 2222.
By first organizing the data, the comparison can be done with a built in function. Much faster and cleaner.
Here is how it might be done (this is the "slow and careful way"):
class c4check {
public static void main(String[] args) {
char grid[][] = {{'e','e','e','e','a','b','a'},
{'e','a','b','a','b','b','a'},
{'e','b','a','a','b','b','a'},
{'e','a','b','b','a','b','b'},
{'e','b','a','b','b','a','a'},
{'e','a','b','a','b','b','a'}};
int ii, jj, ri, ci, di;
String checkGrid[] = new String[25];
// copy rows:
for(ri = 0; ri < 6; ri++) {
String temp = "";
for(ci = 0; ci < 7; ci++) {
temp += grid[ri][ci];
}
checkGrid[ri] = temp;
}
// copy columns:
for(ci = 0; ci < 7; ci++) {
String temp = "";
for(ri = 0; ri < 6; ri++) {
temp += grid[ri][ci];
}
checkGrid[ci + 6] = temp;
}
// copy first diagonals:
for(di = 0; di < 6; di++) {
String temp = "";
for(ri = 0; ri < 6; ri++) {
ci = di - 2;
ri = 0;
while(ci < 0) {
ri++;
ci++;
}
for(; ri < 6; ri++, ci++) {
if( ci > 6 ) continue;
temp += grid[ri][ci];
}
}
checkGrid[di+13] = temp;
}
// diagonals in the other direction:
for(di = 0; di < 6; di++) {
String temp = "";
for(ri = 0; ri < 6; ri++) {
ci = 8 - di;
ri = 0;
while(ci > 6) {
ri++;
ci--;
}
for(; ri < 6; ri++, ci--) {
if( ci < 0 ) continue;
temp += grid[ri][ci];
}
}
checkGrid[di+19] = temp;
}
for(ii = 0; ii < 25; ii++) {
System.out.println("Checking '" + checkGrid[ii] + "'");
if (checkGrid[ii].contains("aaaa")) System.out.println("Player A wins!");
if (checkGrid[ii].contains("bbbb")) System.out.println("Player B wins!");
}
}
}
Obviously, instead of copying temp to an array element, and then checking at the end, you could check for "aaaa" or "bbbb" each time, and return from the function as soon as you found a match.
Output of this particular code (which has more than one "winning" combination, so it's not a "real" situation - but it allowed me to check that all the diagonals were visited correctly):
Checking 'eeeeaba'
Checking 'eababba'
Checking 'ebaabba'
Checking 'eabbabb'
Checking 'ebabbaa'
Checking 'eababba'
Checking 'eeeeee'
Checking 'eababa'
Checking 'ebabab'
Checking 'eaabba'
Checking 'abbabb'
Checking 'bbbbab'
Player B wins!
Checking 'aaabaa'
Checking 'eaaa'
Checking 'ebbbb'
Player B wins!
Checking 'eaabbb'
Checking 'ebaaaa'
Player A wins!
Checking 'eabba'
Checking 'ebbb'
Checking 'abba'
Checking 'ababb'
Checking 'abbbaa'
Checking 'bbabbe'
Checking 'aaaae'
Player A wins!
Checking 'ebbe'
Here is way to maintain the track of winner :-
maintain 4 types of sets (horizontal,vertical,two diagonal).
whenever a point on grid is colored check with corresponding neighbour in the same type eg. if grid point (x,y) is colored then for horizontal type we check (x,y+1) and (x,y-1).
find union of two similar colored neighbour.
If size of any set is equal to four then you have found the winner. You can check while updating neighbours of point currently colored.
Suggestions: Use Union-Find datastructure to achieve good time complexity (Note as your sets are small you can do without it as well).

Treating a bidimensional text (Ruzzle solver)

I am trying to program a Ruzzle solver Java application for learning purpose.
I have a little problem in th ematter of "finding words" in a Ruzzle-type map.
Example of a Ruzzle map (it is composed of 4 rows and 4 columns of 1 letter in each cell) :
Z O O H
E Y L H
I E L I
H O F M
http://www.maclife.com/files/imagecache/futureus_imagegallery_fullsize/gallery/ruzzle1.jpg
I would like to obtain a list of all possible words you can find in such a map.
The difficulty : you can find a word by appending letters vertically, horizontally and diagonally (example : "HELLO").
So far, I created 3 classes :
Ruzzlesolver.java
Letter.java
Map.java
The Letter class
Describes a single Letter of the map, its fields are the X and Y positions and the character of the cell.
The Ruzzlesolver class
This is the main class.
it reads the Ruzzle map (an line by line input in the console)
it reads the dictionnary.txt file
it compares the map with the dictionnary file
it writes into the results.txt file
Each line is stored in a char array.
Then I create a new Map object from the 4 obtained arrays.
The Map class
This is the constructor of the Map objects :
public Map(final char[] pTab1, final char[] pTab2, final char[] pTab3, final char[] pTab4)
{
this.aLettres = new ArrayList<Letter>();
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(1, i+1, pTab1[i]));}
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(2, i+1, pTab2[i]));}
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(3, i+1, pTab3[i]));}
for (int i = 0 ; i < 4 ; i++) {
this.aLettres.add(new Letter(4, i+1, pTab4[i]));}
}
this.aLettres is the ArrayList that contains each of the 16 letters of the map.
Each Letter knows its column (X position : "i+1"), its row (Y position : "1, 2, 3 and 4") and its character ("pTab[i]").
Now that we know the map and the place of each letter, we can begin to find the words.
The contains() method
This is my problem : I am stuck using the following method :
How it is called
I pick a word from the dictionnary in the Ruzzlesolver class.
I call the contains() method on my Map object, with this word as a parameter :
if (this.aMap.contains(vMot)) {/*print vMot in the result.txt file*/}
How does the contains() method work
Variables :
char[] vChars = new char[pMot.length()];
ArrayList<Letter> vFoundCharS1 = new ArrayList<Letter>();
Stocking each characters of pMot in an ArrayList :
for (int i = 0 ; i < pMot.length() ; i++) {
vChars[i] = pMot.charAt(i);
}
Searching for the first character of pMot :
for (Letter vL : this.aLettres) {
if (vL.getChar() == vChars[0]) {
vFoundCharS1.add(vL);
return true;
}
}
I am stuck.
If I continue this method, I will have to create longer and longer blocks as I progress. Besides, I would need to write 16 blocks to consider every length possibility.
I am sure this is a wrong method. How would you implement such a treatment ?
Thanks a lot in advance for your help.
PS : I apologize for grammar/English mistakes, English is not my natal language.
If I understand the problem correctly, you can pick every adjacent cell for the next letter, right? In that case, the code below would (I think) solve your problem.
I changed the constructor of Map, because it is easier to work with a two-dimensional array of char.
The function contains does just what your step 3 described: find the first letter and try searching on from there. The function findRecursively searches for the rest of the word recursively.
public class Map {
private char[][] board;
public Map(final char[] pTab1, final char[] pTab2,
final char[] pTab3, final char[] pTab4) {
board = new char[4][4];
for (int i = 0 ; i < 4 ; i++) {
board[0][i] = pTab1(i);
board[1][i] = pTab2(i);
board[2][i] = pTab3(i);
board[3][i] = pTab4(i);
}
}
public boolean contains(String word) {
char[] array = word.toCharArray();
// empty string is trivial
if (array.length == 0)
return true;
for(int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (board[i][j] == array[0] && findRecursively(i, j, array, 1))
return true;
}
}
return false;
}
public boolean isValid(int i, int j) {
return (0 <= i && i < 4) && (0 <= j && j < 4);
}
public boolean findRecursively(int i, int j, char[] array, int index) {
// reached end of word
if (index == array.length) {
return true;
} else {
// loop over all neighbors
for (int di = -1; di <= 1; di++) {
for (int dj = -1; dj <= 1; dj++) {
// skip cell itself and invalid cells
if (!(di == 0 && dj == 0) && isValid(i+di, j+dj)) {
if (board[i+di][j+dj] == array[index]
&& findRecursively(i+di, j+dj, array, index+1))
return true;
}
}
}
return false;
}
}
}

Incorrect Answer in Broken Necklace Problem USACO [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Broken Necklace
You have a necklace of N red, white, or blue beads (3<=N<=350) some of which are red, others blue, and others white, arranged at random. Here are two examples for n=29:
1 2 1 2
r b b r b r r b
r b b b
r r b r
r r w r
b r w w
b b r r
b b b b
b b r b
r r b r
b r r r
b r r r
r r r b
r b r r r w
Figure A Figure B
r red bead
b blue bead
w white bead
The beads considered first and second in the text that follows have been marked in the picture.
The configuration in Figure A may be represented as a string of b's and r's, where b represents a blue bead and r represents a red one, as follows: brbrrrbbbrrrrrbrrbbrbbbbrrrrb .
Suppose you are to break the necklace at some point, lay it out straight, and then collect beads of the same color from one end until you reach a bead of a different color, and do the same for the other end (which might not be of the same color as the beads collected before this).
Determine the point where the necklace should be broken so that the most number of beads can be collected.
Example
For example, for the necklace in Figure A, 8 beads can be collected, with the breaking point either between bead 9 and bead 10 or else between bead 24 and bead 25.
In some necklaces, white beads had been included as shown in Figure B above. When collecting beads, a white bead that is encountered may be treated as either red or blue and then painted with the desired color. The string that represents this configuration will include the three symbols r, b and w.
Write a program to determine the largest number of beads that can be collected from a supplied necklace.
INPUT FORMAT
Line 1: N, the number of beads
Line 2: a string of N characters, each of which is r, b, or w
29
wwwbbrwrbrbrrbrbrwrwwrbwrwrrb
OUTPUT FORMAT
A single line containing the maximum of number of beads that can be collected from the supplied necklace.
11
OUTPUT EXPLANATION
Consider two copies of the beads (kind of like being able to runaround the ends). The string of 11 is marked.
Two necklace copies joined here
wwwbbrwrbrbrrbrbrwrwwrbwrwrrb | wwwbbrwrbrbrrbrbrwrwwrbwrwrrb
******|*****
rrrrrb|bbbbb <-- assignments
5xr .....#|##### 6xb
5+6 = 11 total
This is a USACO training problem i'm having trouble with; i keep getting incorrect answers. ...and please don't tell me this is stupid or silly; that's not helping! :D
Heh, I'm up to this one but I haven't been bothered to code it up. Anyway, my ideas are this.
Firstly, you don't need to store all the bead colours (Go Australian spelling!), you just need to store how many beads of the same colour are in a row. So for:
RRBBBWRR
you just need to store:
2R 3B 1W 2R
One thing to note is if the ending and the starting beads are the same colour you have to account for that, so
RRBBBRR
should be stored as
4R 3B
or
3B 4R
Same thing. Note that the reason for this is not to save memory or anything, but to ensure that beads next to each other are different colours. We have done this by combining beads of the same colour.
Next is you go through each one:
- If it's red, you add up all the ones after that till you find a blue and then continue adding until you find another red
- If it's blue, do similarly except reversed
- If it's white, then the next bead will be red or blue. Do as above except with the number of white beads added
Here are some examples. The |'s mark where the sequence begins and ends.
B|RB|R
we find a R then a B then another R. Therefore we have to stop at the B. In
B|RWRB|R
We find an R and then another R but we haven't found a B yet so we continue. Then we find a B and then another R. This time, since we've found a B we have to stop.
B|RBW|R
we find a R then a B but we can continue since the next one is a W, then we find another R so we have to stop. In
B|WRBWB|R
we count the W then we find a R. Therefore we continue till we find a B and then continue till we find another R. This
B|WBRWR|B
is a reverse case.
Now all you have to do is implement it :D. Of course this doesn't take into account the actual number of beads in the the R, B and W and are just examples of single bead sequences. You will have to check all possible sequences. You also have to take care of the sequences which wrap around from the back to the start.
Lastly, you may notice that this algorithm is sometimes wasteful but N < 350 so even an O(N^3) should work in 1 second. Maybe 2. Anyway, I believe this is O(N^2) so you should be able to run this program 350 times in one second. Please comment if something's confusing because I'm not the best explainer. Happy coding.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
int main(){
int numBeads;
char temp1[705];
char temp2[705];
int i,j,k,lim;
int count1 = 0;
int count2 = 0;
int maxcount1 = 0;
char virgin = ' ';
bool flag = false; //flag == true if virgin doesn't match
FILE* fin = fopen("beads.in","r");
FILE* fout = fopen("beads.out","w");
fscanf(fin,"%d",&numBeads);
fscanf(fin,"%s",temp1);
strcpy(temp2,temp1);
strcat(temp1,temp2);
for(i=0,j=numBeads-1;i<numBeads;i++,j++){
count1 =0;
count2 = 0;
flag = false;
virgin = ' ';
for(k=i;flag==false && k < (i+numBeads);k++){
if(temp1[k]=='w'){
count1++;
}
else if(temp1[k]=='r'){
if(virgin==' '){
virgin = 'r';
}
if(virgin=='r')
count1++;
else{
flag = true;
k--;
}
}
else if(temp1[k]=='b'){
if(virgin==' '){
virgin = 'b';
}
if(virgin=='b')
count1++;
else{
flag = true;
k--;
}
}
}
/* Block 2*/
lim = k;
flag = false;
virgin = ' ';
for(k=j;flag==false && k < (j+numBeads) && k>=lim;k--){
if(temp1[k]=='w'){
count2++;
}
else if(temp1[k]=='r'){
if(virgin==' '){
virgin = 'r';
}
if(virgin=='r')
count2++;
else{
flag = true;
k--;
}
}
else if(temp1[k]=='b'){
if(virgin==' '){
virgin = 'b';
}
if(virgin=='b')
count2++;
else{
flag = true;
k--;
}
}
}
if(maxcount1 < (count1+ count2))maxcount1 = count1 + count2;
}
fprintf(fout,"%d\n",maxcount1);
return 0;
}
Here is my code:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
/**
*
* #author Bansari
*/
public class beads {
public static void main(String args[]){
try{
BufferedReader f = new BufferedReader(new FileReader("beads.in"));
// input file name goes above
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("str.txt")));
int len = Integer.parseInt(f.readLine());
String s=f.readLine();
int c1=0,c2=0;
int breakpoint=0;
int max = 0;
for(int i = 1;i<=len;i++){
char before = s.charAt((i-1)%len);
char after = s.charAt(i%len);
if(before != after){
c1=0;
c2=0;
int index = i-1;
while(s.charAt(index)==before || s.charAt(index)=='w'){
char sc = s.charAt(index);
c1++;
if(index==0)
index = len-1;
else
index--;
}
index = i;
while(s.charAt(index%len)==after || s.charAt(index%len)=='w'){
c2++;
if(index == len-1)
index = 0;
else
index++;
}
if(max < (c1 + c2)){
breakpoint=i;
max = c1+c2;
}
}
}
out.println(max);
out.close();
System.exit(0);
}catch(Exception e){
}
}
}
When you're presented with a weird problem in a computing contest, it's odds-on it'll be dynamic programming (the Bellman kind, not the Ruby kind.)
Have a look at this tutorial.
The basic idea of dynamic programming is to build up a "big" answer by answering small subproblems. My first intuitive thought is to think about longer and longer necklaces, starting with, like, one bead, but I'm honestly not particularly good at dynamic programming problems. (I've also noticed that the most common place to run into DP problems in the real world is in computing olympiads and problem sets in computer science classes.)
RETRACTED -- THIS IS WRONG because it does not consider white beads.
i can either see a simpler than the accepted answer, or the explanation is too complex. here's the algorithm in pseudocode (ignoring the case of all same color):
p = position of first bead of different color than bead 0
create array of run-lengths: r={5,15,2,9,13}
create array of sums of adjacents s={20,17,11,22,18} (wrap last)
find index, k, in s[] of max sum: here it is s[3]
position = p + r[0] + r[1] + ... + r[k]
I did this a long long time ago when I was learning programming. I just searched my computer and found the solution that I had submitted. I can provide the code but its all messed up . =P
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
public class beads {
/**
* #param args
* #throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
new beads().go();
}
private void go() throws Exception {
// TODO Auto-generated method stub
BufferedReader bin = new BufferedReader(new FileReader("beads.in"));
PrintWriter pout = new PrintWriter(new BufferedWriter(new FileWriter("beads.out")));
int count = Integer.parseInt(bin.readLine());
String beads = bin.readLine();
int ans = compute(beads);
pout.println(ans);
pout.close();
}
private int compute(String beads) {
// TODO Auto-generated method stub
int length = beads.length();
int maxbeads = 0;
for(int i = 0; i < length; i++){
int left = 0;
int right = 0;
left = computeLeft(beads,i);
if(left == length){ maxbeads = left; break;}
right = computeRigtht(beads,i);
if(right == length){ maxbeads = right; break;}
if((left+right) > maxbeads) maxbeads = left+right;
if(maxbeads == length) break;
}
return maxbeads;
}
private int computeLeft(String beads, int i) {
// TODO Auto-generated method stub
int l = beads.length();
int j = i;
int count = 0;
char ch = beads.charAt(i);
for(; j >=0; j--){
if(ch == 'w'){//Didnt notice this kind of case before
ch = beads.charAt(j);
count++;
}
else if(beads.charAt(j) == ch || beads.charAt(j)== 'w'){
count++;
}
else break;
}
if(j < 0) j = l-1;
for(; j > i; j--){
if(beads.charAt(j) == ch || beads.charAt(j)== 'w'){
count++;
}
else break;
}
return count;
}
private int computeRigtht(String beads, int i) {
// TODO Auto-generated method stub
int l = beads.length();
int j = 0;
if(i == l-1) j = 0;
else j = i+1;
int k = j;
int count = 0;
int ch = beads.charAt(j);
for(; j <l; j++){
if(ch == 'w'){
ch = beads.charAt(j);
count++;
}
else if(beads.charAt(j)== ch || beads.charAt(j)=='w'){
count++;
}
else break;
}
if(j == l) j = 0;
for(; j < k-1; j++){
if(beads.charAt(j) == ch || beads.charAt(j)== 'w'){
count++;
}
else break;
}
return count;
}
}
I used quasiverse's algo and solved it.
The USACO server is down and I am not able to test it on their judge, but I think I have solved it.
#include<iostream>
#include<fstream>
#include<string>
#include<cstring>
#include<cstdlib>
#define MAXLEN 350
using namespace std;
ofstream fout ("beads.out");
typedef struct node
{
char color;
int times;
int lenMax;
struct node* next;
} nodeList;
nodeList * getnode()
{
nodeList* temp=(nodeList*) malloc (sizeof(nodeList));
temp->next=NULL;
temp->lenMax=0;
return temp;
}
void append(nodeList **head,char tColor,int m)
{
nodeList *p=NULL,*newNode=NULL;
newNode =getnode();
newNode->color=tColor;
newNode->times=m;
newNode->lenMax=0;
if(*head==NULL)
{
*head=newNode;
return;
}
p=*head;
while(p->next)
p=p->next;
p->next=newNode;
}
void shiftNodes(nodeList **head)
{
int mon=0;
nodeList *last=NULL,*p=NULL,*t=NULL;
p=*head;
do
{
//cout<<p->color<<" "<<p->times<<endl;
last=p;
p=p->next;
}
while(p!=NULL);
p=*head;
last->next=*head;
t=*head;
do
{
if(((*head)->color=='w' || (last)->color=='w' ) || (*head)->color==last->color)
{
(*head)=(*head)->next;
last=last->next;
}
else if((*head)->color!=last->color )
{
break;
}
p=p->next;
}
while(p!=t);
}
void computeLenMaxB(nodeList ** head)
{
nodeList *p =NULL,*t=NULL,*s=NULL;
t=p=*head;
bool gotR=false;
int tempLenMax=0;
do
{
if(p->color=='b' && gotR){
break;
}
else if(p->color=='b' && !gotR){
tempLenMax+=p->times;
}
else if(p->color=='r' && !gotR){
tempLenMax+=p->times;
gotR=true;
}
else if(p->color=='r' && gotR){
tempLenMax+=p->times;
}
else if(p->color=='w' ){
tempLenMax+=p->times;
}
p=p->next;
}
while(p!=t);
(*head)->lenMax=tempLenMax;
}
void computeLenMaxR(nodeList ** head)
{
nodeList *p =NULL,*t=NULL,*s=NULL;
t=p=*head;
bool gotR=false;
int tempLenMax=0;
do
{
if(p->color=='r' && gotR){
break;
}
else if(p->color=='r' && !gotR){
tempLenMax+=p->times;
}
else if(p->color=='b' && !gotR){
tempLenMax+=p->times;
gotR=true;
}
else if(p->color=='b' && gotR){
tempLenMax+=p->times;
}
else if(p->color=='w' ){
tempLenMax+=p->times;
}
p=p->next;
}
while(p!=t);
(*head)->lenMax=tempLenMax;
}
void fillLenMax(nodeList ** head)
{
nodeList *p =NULL,*t=NULL,*s=NULL;
t=p=*head;
int wBeads=0;
do
{
s=p;
if(p->color=='b')
{
computeLenMaxB(&p);
}
else if(p->color=='r')
{
computeLenMaxR(&p);
}
else if(p->color=='w')
{
if(p->next->color=='b'){
computeLenMaxB(&p);
}
else if(p->next->color=='r'){
computeLenMaxR(&p);
}
}
p=p->next;
}
while(p!=t);
}
int calcMaxLenMax(nodeList *head)
{
nodeList *p=NULL;
p=head;
int max=0;
do
{
//fout<<p->color<<" "<<p->times<<" "<<p->lenMax<<endl;
max=(max>p->lenMax)?max:p->lenMax;
p=p->next;
}
while(p!=head);
return max;
}
int main()
{
ifstream fin ("beads.in");
char necklace[MAXLEN];
int i,j,max;
fin>>necklace;
nodeList* list=NULL;
int repeat = 0;
i=0;
while(i<strlen(necklace))
{
repeat = 0;
for(j=i; necklace[j]==necklace[i]; j++)
{
repeat++;
}
append(&list ,necklace[i],repeat);
i=i+repeat;
}
shiftNodes(&list);
fillLenMax(&list);
max=calcMaxLenMax(list);
fout<<max<<endl;
return 0;
}
Its an old thread, but might be useful to people learning programming. Here is a simple solution using brute force. The idea is that we make one pass through the data to count colours. In the second loop we perform pairwise comparison of sums from the left and the right part. Code should be easy to follow:
import java.io.*;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
public class beads {
public static void main(String[] args) throws IOException {
BufferedReader f = new BufferedReader(new FileReader("beads.in"));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("beads.out")));
f.readLine();//length
String s1 = f.readLine();
List<String> counts = new LinkedList<String>();
char[] colors = (s1.concat(s1)).toCharArray();
char previousColor = ' ';
int count = 0;
for (char color : colors) {
if (previousColor != color && count > 0) {
counts.add(count + "-" + previousColor);
count = 0;
}
count++;
previousColor = color;
}
if (counts.isEmpty()) {//special case when there is only one color
out.println(count/2);
out.close();
System.exit(0);
}
TreeSet<Integer> result = new TreeSet<Integer>();
for (int i = 1; i < counts.size(); i++) {
if(counts.get(i).split("-")[1].charAt(0)=='w')continue;
int left = getLeft(counts, i);
int right = getRight(counts, i);
result.add((left+right));
}
out.println(result.last());
out.close();
System.exit(0);
}
private static int getLeft(List<String> counts, int i) {
char start = counts.get(i - 1).split("-")[1].charAt(0);
boolean doContinue = true;
int count = 0;
while (doContinue) {
String[] s = counts.get(--i).split("-");
char color=s[1].charAt(0);
if(start=='w' && color!='w')start=color;
boolean incr = (color == 'w' || color==start);
if(incr)
count += Integer.parseInt(s[0]);
else doContinue=false;
doContinue = doContinue && i > 0;
}
return count;
}
private static int getRight(List<String> counts, int i) {
char start = counts.get(i).split("-")[1].charAt(0);
boolean doContinue = true;
int count = 0;
while (doContinue) {
String[] s = counts.get(i).split("-");
char color=s[1].charAt(0);
if(start=='w' && color!='w')start=color;
boolean incr = (color == 'w' || color == start);
if(incr)
count += Integer.parseInt(s[0]);
else doContinue=false;
doContinue = doContinue && ++i < counts.size()-1;
}
return count;
}
}
This is a teaser! Every time solution is just so, so close!
In the meantime the white beads are cause of black despair.
Here is the algorithm (I passed Usaco grader)
1) find first colored bead. say it is at position k in the n bead necklace
2) rearrange necklace: move the section 0-k to the end ,so it starts with true color.
e.g {wwbrwbrb{ becomes {brwbrbww}
3) cut up the necklace into sub-sections (array of strings), so that each section starts with a color e.g. {b rw b r bww}
4) if first and last segment are the same color, join them
e.g. {b rw bw rw bww} becomes {bwwb rw bw rw} (sequence is preserved)
5) Notice!!!! the second last element (bw) ends with white. So white can be joined to rw that follows.
Also notice that following sequence will never starts with white.
6) for each entry in the array of sub sequences add lengths of entry k and k+1.
Then skim the white spaces (if any) from the entry k-1 and add to the above (since this is a circle then k-1 entry may be the last in the array).
if bigger than max then change max.
There is some tricky accounting for less than three sub sequences in the necklace but it is just tedious, no trick to it.

Categories

Resources