Minimum time required to rot all oranges - java

Given a matrix of dimension r*c where each cell in the matrix can have values 0, 1 or 2 which has the following meaning:
0 : Empty cell
1 : Cells have fresh oranges
2 : Cells have rotten oranges
So, we have to determine what is the minimum time required to rot all oranges. A rotten orange at index [i,j] can rot other fresh orange at indexes [i-1,j], [i+1,j], [i,j-1], [i,j+1] (up, down, left and right) in unit time. If it is impossible to rot every orange then simply return -1.
Input:
The first line of input contains an integer T denoting the number of test cases. Each test case contains two integers r and c, where r is the number of rows and c is the number of columns in the array a[]. Next line contains space separated r*c elements each in the array a[].
Here is the Code I have written
class GFG {
public static boolean isSafe(int[][] M, boolean[][] visited, int i, int j) {
int R = M.length;
int C = M[0].length;
return (i >= 0 && i < R && j >= 0 && j < C && (!visited[i][j]) && M[i][j] != 0);
}
public static int findMinDist(int[][] M, boolean[][] visited, int i, int j, int dist) {
if (M[i][j] == 2)
return dist;
int[] x_pos = { 1, -1, 0, 0 };
int[] y_pos = { 0, 0, -1, 1 };
visited[i][j] = true;
int min = Integer.MAX_VALUE;
for (int k = 0; k < 4; k++) {
if (isSafe(M, visited, i + x_pos[k], j + y_pos[k]))
min = Math.min(min, findMinDist(M, visited, i + x_pos[k], j + y_pos[k], dist + 1));
}
return min;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
for (int t = 0; t < T; t++) {
int R = sc.nextInt();
int C = sc.nextInt();
int[][] M = new int[R][C];
boolean[][] visited = new boolean[R][C];
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
M[i][j] = sc.nextInt();
}
}
int[][] time = new int[R][C];
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
if (M[i][j] == 1)
time[i][j] = findMinDist(M, new boolean[R][C], i, j, 0);
}
}
int maxTime = Integer.MIN_VALUE;
for (int i = 0; i < R; i++) {
for (int j = 0; j < C; j++) {
maxTime = Math.max(time[i][j], maxTime);
}
}
System.out.println(maxTime == Integer.MAX_VALUE ? -1 : maxTime);
}
}
}
I am trying to find minimum distance of 2 from each 1.
It is not working for test case
Input:
1
2 5
1 1 1 1 1 0 2 1 1 1
Its Correct output is:
4
And My Code's output is:
6
Please suggest what's wrong with the code.

Start by creating a matrix to store the times the oranges rot. You can initialize all slots with -1. You will use BFS but you won't need a "marked" matrix, because the times the oranges rot will already be enough to tell you if a slot has been visited or not.
Iterate through the original matrix. When you find a value 2, do a BFS starting there to rot the fresh oranges. This BFS should also state the time when each orange is rot and you must always keep the smallest time. If the orange being looked at the moment was already rotten at time t1 and you've just got there in time t2, where t2 < t1, pretend this orange is fresh and put it into the BFS queue like so.
After finishing it, iterate through the matrix of times and return the biggest value found.

class Pair {
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
public int x;
public int y;
}
public class Solution {
public static boolean isSafe(int x, int y, int r, int c) {
return (x >= 0) && (x < r) && (y >= 0) && (y < c);
}
public static boolean isFreshOrageLeft(int[][] grid) {
int r = grid.length;
int c = grid[0].length;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j] == 1)
return true;
}
}
return false;
}
public static int orangesRotting(int[][] grid) {
int r = grid.length;
int c = grid[0].length;
int count = 0;
boolean flag = false;
Queue<Pair> q = new LinkedList<>();
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (grid[i][j] == 2)
q.add(new Pair(i, j));
}
}
q.add(new Pair(-1, -1));
while (!q.isEmpty()) {
while (q.peek().x != -1 && q.peek().y != -1) {
Pair p = q.poll();
int leftX = p.x - 1;
int leftY = p.y;
if (isSafe(leftX, leftY, r, c) && grid[leftX][leftY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[leftX][leftY] = 2;
q.add(new Pair(leftX, leftY));
}
int rightX = p.x + 1;
int rightY = p.y;
if (isSafe(rightX, rightY, r, c) && grid[rightX][rightY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[rightX][rightY] = 2;
q.add(new Pair(rightX, rightY));
}
int upX = p.x;
int upY = p.y + 1;
if (isSafe(upX, upY, r, c) && grid[upX][upY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[upX][upY] = 2;
q.add(new Pair(upX, upY));
}
int downX = p.x;
int downY = p.y - 1;
if (isSafe(downX, downY, r, c) && grid[downX][downY] == 1) {
if (!flag) {
count++;
flag = true;
}
grid[downX][downY] = 2;
q.add(new Pair(downX, downY));
}
}
flag = false;
q.poll();
if (!q.isEmpty())
q.add(new Pair(-1, -1));
}
return isFreshOrageLeft(grid)?-1:count;
}
public static void main(String[] args) {
int[][] grid = {{2,2,0,1}};
System.out.println(orangesRotting(grid));
}
}

Related

Rotten Oranges LeetCode

I'm trying to solve this problem: https://leetcode.com/problems/rotting-oranges/
The link explains better than I can with the visuals, but basically you have to make every orange that's next to a "rotten" one (value 2) rotten as well.
I'm approaching this using a BFS. I start by making a queue for all the rotten oranges, then I pass that to my bfs function which checks if going (up/down/left/right) is possible and if it is then adds that to the queue and changes the value to show the node has already been visited.
My solution is not giving me the right answer and I'm not sure where the logical misstep is.
class Solution {
public int orangesRotting(int[][] grid) {
//get all 2's into a queue
//iterate over 2 making all oranges rotten
//iterate grid again --> anything that's not 2, return -1
//else return count
Queue<String> q = new LinkedList<>();
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[i].length; j++) {
if(grid[i][j] == 2) {
q.add("" + i + j);
}
}
}
int count = getMinutes(grid, q);
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[i].length; j++) {
if(grid[i][j] == 1) {
return -1;
}
}
}
return count;
}
public static int getMinutes(int[][] grid, Queue<String> q) {
Queue<String> rotten = new LinkedList<>();
int count = 0;
final int[][] SHIFTS = {
{1,0},
{-1,0},
{0,1},
{0,-1}
};
while(true) {
while(!q.isEmpty()) {
String s = q.remove();
int i = Integer.parseInt(s.substring(0, s.length() - 1));
int j = Integer.parseInt(s.substring(s.length() - 1));
for(int[] points : SHIFTS) {
int tempI = i + points[0];
int tempJ = j + points[1];
if(isValidMove(grid, tempI, tempJ)) {
rotten.add("" + tempI + tempJ);
grid[tempI][tempJ] = 2; //it's visited
}
}
}
if(rotten.isEmpty()) {
return count;
}
count++;
q = rotten;
}
}
public static boolean isValidMove(int[][] grid, int i, int j) {
if(i < 0 || i >= grid.length || j < 0 || j >= grid[i].length || grid[i][j] != 1) {
return false;
}
return true;
}
}
I suggest you don't do this : q.add("" + i + j); How would you distinguish between {11,2} and {1, 12}, both give the same string "112"? Just use q.add( new int[]{i, j} ) it shouldn't cause too much of a performance problem they are just ints. In fact its the other way around. It should be faster.
Now coming to the main issue, your algorithm is almost correct except for the fact that you need to initialize a new Queue inside while ( true ) because you have to start with a new queue every time you flush your current queue. The idea is you start with a queue of already rotten oranges. Rot their neighboring oranges and build a new queue consisting of the newly rotten oranges. Then repeat until your new queue of newly rotten oranges is empty. So it has to be a new queue everytime you start with already rotten oranges.
The modified getMinutes with the correction of the main issue is :
public static int getMinutes(int[][] grid, Queue<String> q) {
int count = 0;
final int[][] SHIFTS = {
{1,0},
{-1,0},
{0,1},
{0,-1}
};
while(true) {
Queue<String> rotten = new LinkedList<>();
while(!q.isEmpty()) {
String s = q.remove();
int i = Integer.parseInt(s.substring(0, s.length() - 1));
int j = Integer.parseInt(s.substring(s.length() - 1));
for(int[] points : SHIFTS) {
int tempI = i + points[0];
int tempJ = j + points[1];
if(isValidMove(grid, tempI, tempJ)) {
rotten.add("" + tempI + tempJ);
grid[tempI][tempJ] = 2; //it's visited
}
}
}
if(rotten.isEmpty()) {
return count;
}
count++;
q = rotten;
}
}
Looks pretty good!
My guess is that your solution is missing return 0 for if there is no freshOranges early.
This is similarly a Breadth First Search algorithm, crammed into one function though for laziness purposes ( ˆ_ˆ ):
public class Solution {
private static final int[][] directions = new int[][] {
{1, 0},
{ -1, 0},
{0, 1},
{0, -1}
};
public static final int orangesRotting(
int[][] grid
) {
final int rows = grid.length;
final int cols = rows > 0 ? grid[0].length : 0;
if (rows == 0 || cols == 0) {
return 0;
}
Queue<int[]> queue = new LinkedList<>();
int freshOranges = 0;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (grid[row][col] == 2) {
queue.offer(new int[] {row, col});
} else if (grid[row][col] == 1) {
freshOranges++;
}
}
}
if (freshOranges == 0) {
return 0;
}
int count = 0;
while (!queue.isEmpty()) {
count++;
final int size = queue.size();
for (int i = 0; i < size; i++) {
final int[] cell = queue.poll();
for (int[] direction : directions) {
final int row = cell[0] + direction[0];
final int col = cell[1] + direction[1];
if (
row < 0 ||
col < 0 ||
row >= rows ||
col >= cols ||
grid[row][col] == 0 ||
grid[row][col] == 2
) {
continue;
}
grid[row][col] = 2;
queue.offer(new int[] {row, col});
freshOranges--;
}
}
}
return freshOranges == 0 ? count - 1 : -1;
}
}

Java: Sudoku- increase number of empty spaces causes my code to throw an exception

I'm trying to make a Sudoku game for my project but if i increase the number of empty spaces in the Sudoku Grid the code just throws an exception arrayoutofbounds but can't figure out where it's coming from. k is the number of empty spaces in the grid.
I haven't tried anything because can't figure out what can be done at this kind of problem
Here is the code:
package sudoku.puzzle;
import java.util.*;
public class SudokuPuzzle {
int[] mat[];
int N; // number of columns/rows.
int SRN; // square root of N
int K; // No. Of missing digits
// Constructor
SudokuPuzzle(int N, int K) {
this.N = N;
this.K = K;
// Compute square root of N
Double SRNd = Math.sqrt(N);
SRN = SRNd.intValue();
mat = new int[N][N];
}
// Driver code
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Select Level Of Difficulty \n 1.Easy\n 2.Medium\n 3.Hard");
String Choice = in .next(); in .close();
if ("1".equals(Choice) || "Easy".equals(Choice) || "easy".equals(Choice) || "e".equals(Choice) || "E".equals(Choice)) {
int N = 9, K = 40;
SudokuPuzzle sudoku = new SudokuPuzzle(N, K);
sudoku.fillValues();
sudoku.printSudoku();
}
if ("2".equals(Choice) || "Medium".equals(Choice) || "medium".equals(Choice) || "m".equals(Choice) || "M".equals(Choice)) {
int N = 9, K = 60;
SudokuPuzzle sudoku = new SudokuPuzzle(N, K);
sudoku.fillValues();
sudoku.printSudoku();
}
if ("3".equals(Choice) || "Hard".equals(Choice) || "hard".equals(Choice) || "h".equals(Choice) || "H".equals(Choice)) {
int N = 9, K = 72;
SudokuPuzzle sudoku = new SudokuPuzzle(N, K);
sudoku.fillValues();
sudoku.printSudoku();
}
}
// Sudoku Generator
public void fillValues() {
// Fill the diagonal of SRN x SRN matrices
fillDiagonal();
// Fill remaining blocks
fillRemaining(0, SRN);
// Remove Randomly K digits to make game
removeKDigits();
}
// Fill the diagonal SRN number of SRN x SRN matrices
void fillDiagonal() {
for (int i = 0; i < N; i = i + SRN)
// for diagonal box, start coordinates->i==j
fillBox(i, i);
}
// Returns false if given 3 x 3 block contains num.
boolean unUsedInBox(int rowStart, int colStart, int num) {
for (int i = 0; i < SRN; i++)
for (int j = 0; j < SRN; j++)
if (mat[rowStart + i][colStart + j] == num)
return false;
return true;
}
// Fill a 3 x 3 matrix.
void fillBox(int row, int col) {
int num;
for (int i = 0; i < SRN; i++) {
for (int j = 0; j < SRN; j++) {
do {
num = randomGenerator(N);
}
while (!unUsedInBox(row, col, num));
mat[row + i][col + j] = num;
}
}
}
// Random generator
int randomGenerator(int num) {
return (int) Math.floor((Math.random() * num + 1));
}
// Check if safe to put in cell
boolean CheckIfSafe(int i, int j, int num) {
return (unUsedInRow(i, num) &&
unUsedInCol(j, num) &&
unUsedInBox(i - i % SRN, j - j % SRN, num));
}
// check in the row for existence
boolean unUsedInRow(int i, int num) {
for (int j = 0; j < N; j++)
if (mat[i][j] == num)
return false;
return true;
}
// check in the row for existence
boolean unUsedInCol(int j, int num) {
for (int i = 0; i < N; i++)
if (mat[i][j] == num)
return false;
return true;
}
// A recursive function to fill remaining
// matrix
boolean fillRemaining(int i, int j) {
// System.out.println(i+" "+j);
if (j >= N && i < N - 1) {
i = i + 1;
j = 0;
}
if (i >= N && j >= N)
return true;
if (i < SRN) {
if (j < SRN)
j = SRN;
} else if (i < N - SRN) {
if (j == (int)(i / SRN) * SRN)
j = j + SRN;
} else {
if (j == N - SRN) {
i = i + 1;
j = 0;
if (i >= N)
return true;
}
}
for (int num = 1; num <= N; num++) {
if (CheckIfSafe(i, j, num)) {
mat[i][j] = num;
if (fillRemaining(i, j + 1))
return true;
mat[i][j] = 0;
}
}
return false;
}
// Remove the K no. of digits to
// complete game
public void removeKDigits() {
int count = K;
while (count != 0) {
int cellId = randomGenerator(N * N);
// System.out.println(cellId);
// extract coordinates i and j
int i = (cellId / N);
int j = cellId % 9;
if (j != 0)
j = j - 1;
// System.out.println(i+" "+j);
if (mat[i][j] != 0) {
count--;
mat[i][j] = 0;
}
}
}
// Print sudoku
public void printSudoku() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++)
System.out.print(mat[i][j] + " ");
System.out.println();
}
System.out.println();
}
}
What you got is probably a ArrayIndexOutOfBoundsException. That means at some point you try to access a field of an array outside its boundaries.
But I can´t see where K could be responsible for that. Can you provide more information about the error? E.g. at which value you get it or in which line.
EDIT: The variable i int the removeKDigits() function exceeds the boundaries of the array if the random generator spits out the value 81.

Game of Life, java objects

On my program for java programming is not running right. My professor had us download a console.java to help use make a console to display our outputs of the program. I think the program is getting stuck when I am calling the update method and checkCells. My professor said that calling matrix.length for both rows and columns is incorrect but I'm stumped on how to call columns if I am not using matrix.length.
Any input is appreciated
import java.util.*;
public class Life {
private int birthLow = 0;
private int birthHigh = 0;
private int liveLow = 0;
private int liveHigh = 0;
private boolean[][] matrix;
public Life(long seed, int rows, int cols, int birthLow2, int birthHigh2, int liveLow2, int liveHigh2) {
boolean initalMatrix[][] = new boolean[rows][cols];
seedArray(initalMatrix, rows, cols, seed);
birthLow = birthLow2;
birthHigh = birthHigh2;
liveLow = liveLow2;
liveHigh = liveHigh2;
matrix = initalMatrix;
if ((rows < 1) && (cols < 1)) {
throw new IllegalArgumentException("Rows must be positive, not " + rows);
}
if ((rows > 9) && (cols < 9)) {
throw new IllegalArgumentException("Rows and cols cant go over 9, not " + rows + cols);
}
if (birthLow < 1 || (birthHigh > 9) || (liveLow < 1) || (liveHigh > 9)) {
throw new IllegalArgumentException("birth rates can not be below 1 or above 9 " + birthLow + birthHigh);
}
}
public boolean[][] world() {
boolean[][] matrixClone = matrix.clone();
for (int row = 0; row < matrix.length; row++) {
matrixClone[row] = matrix[row].clone();
}
return matrixClone;
}
public void update() {
matrix = checkCells(matrix, matrix.length, matrix.length, birthLow, birthHigh, liveLow, liveHigh);
}
public static void seedArray(boolean[][] matrix, int rows, int cols, long seed) {
// generates a random seed to fill the matrix
Random s = new Random(seed);
for (int r = 1; r < rows - 1; r++) {
for (int c = 1; c < cols - 1; c++) {
boolean x = s.nextBoolean();
matrix[r][c] = x;
}
}
}
public static void printBoard(boolean[][] matrix, int rows, int cols) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (matrix[r][c] == false && c == 0) {
System.out.print("- ");
} else if (matrix[r][c] == false && c > 0) {
System.out.print("- ");
} else if (matrix[r][c] == true) {
System.out.print("# ");
}
}
System.out.println();
}
System.out.println();
}
public static boolean[][] checkCells(boolean[][] matrix, int rows, int cols, int birthLow, int birthHigh,
int liveLow, int liveHigh) {
// clones matrix board
boolean[][] matrixClone = matrix.clone();
for (int row = 0; row < matrix.length; row++) {
matrixClone[row] = matrix[row].clone();
}
// determines if the living cell is going to live or die
for (int r = 1; r < rows; r++) {
for (int c = 1; c < cols; c++) {
if (neighbors(matrixClone, r, c) < liveLow || neighbors(matrixClone, r, c) > liveHigh || c == 0
|| r == 0 || c == cols - 1 || r == rows - 1) {
matrix[r][c] = false;
} else if (neighbors(matrixClone, r, c) >= birthLow && neighbors(matrixClone, r, c) <= birthHigh) {
matrix[r][c] = true;
}
}
}
return matrixClone;
}
public static int neighbors(boolean[][] matrixClone, int r, int c) {
int neighbors = 0;
// checks all neighbors for life or death
for (int rn = (r - 1); rn <= (r + 1); rn++) {
for (int cn = (c - 1); cn <= (c + 1); cn++) {
try {
if (matrixClone[rn][cn] == true) {
neighbors++;
}
// catches the array if it checks out the perimeter
} catch (ArrayIndexOutOfBoundsException f) {
continue;
}
}
}
return neighbors;
}
}
Don't use matrix.length for columns. You already know that. The reason is that it gives you the number of rows. Instead, just save the values of row and col and use them.
One way to do that is to make them fields, and initialize them in your constructor.
Do not initialize a random boolean[][] called initialMatrix. Instead, initialize the boolean[][] matrix that you have in the fields up above (matrix = new boolean[rows][cols]). Then for seedArray, call seedArray(matrix, rows, cols, seed).
Finally, in the update() method, do not use matrix.length, but rather rows and cols.

I am trying to write a quickSort method as part of an assignment, but I keep getting a StackOverflow error in Java

This is the code for my sorting attempt. After running for about ten minutes in Eclipse's debugger mode, I got a lot of StackOverFlow errors. This was my output display:
Exception in thread "main" java.lang.StackOverflowError
at TestSorter.Tester.sort(Tester.java:6)
... (x112 repetitions of at TestSorter.Tester.sort(Tester.java:49))
at TestSorter.Tester.sort(Tester.java:49)
public static int[] sort(int[] a) {
int prod = (a.length)/2, b = lessThan(a, prod), c = greaterThan(a, prod), d = equalTo(a, prod);
int[] first, last, mid;
first = new int[b];
last = new int[c];
mid = new int[d];
int[] fina = new int[a.length];
int f = 0, l = 0, m = 0;
if (isSorted(a))
return a;
for (int x = 0; x < a.length; x++) {
if (a[x] < prod) {
first[f] = a[x];
f++;
}
else if (a[x] > prod) {
last[l] = a[x];
l++;
}
else if (a[x] == prod) {
mid[m] = a[x];
m++;
}
}
if (m == a.length)
return a;
first = sort(first);
last = sort(last);
for (int x = 0; x < b; x++) {
fina[x] += first[x];
}
for (int x = 0; x < d; x++) {
fina[x + b] = mid[x];
}
for (int x = 0; x < c; x++) {
fina[x + b + c] = last[x];
}
return fina;
}
My support methods are as follows:
private static int lessThan(int[] a, int prod) {
int less = 0;
for (int x = 0; x < a.length; x++) {
if (a[x] < prod) {
less++;
}
}
return less;
}
private static int greaterThan(int[] a, int prod) {
int greater = 0;
for (int x = 0; x < a.length; x++) {
if (a[x] > prod) {
greater++;
}
}
return greater;
}
private static int equalTo(int[] a, int prod) {
int equal = 0;
for (int x = 0; x < a.length; x++) {
if (a[x] == prod) {
equal++;
}
}
return equal;
}
private static boolean isSorted(int[] a) {
for (int x = 0; x < a.length - 1; x++) {
if (a[x] > a[x + 1])
return false;
}
return true;
}
Presumably the trouble is that your "prod" is not within the domain of your array. Thus either "first" or "last" is the same size as the input array, and you have an infinite recursion. Try setting prod to be an element in the array you are trying to sort.
THREE POINTS:
The pord should be the mid-element of the array, NOT the half of the array's length.
So, it should be prod =a[(a.length) / 2],
NOT prod =(a.length) / 2
If the array first only have 1 element, it does not need invoke the method sort any more.
Also the last.
So, add if statement:
if (1 < first.length) {
first = sort(first);
}
When you append the element of last to fina, the index should be x+b+d, it means first elements(b) + mid elements(d). NOT x+b+c.
So, change fina[x + b + c] = last[x]; to fina[x + b + d] = last[x];
Well, the method sort maybe like this:
public static int[] sort(int[] a) {
int prod =a[(a.length) / 2], b = lessThan(a, prod), c = greaterThan(a,
prod), d = equalTo(a, prod);
int[] first, last, mid;
first = new int[b];
last = new int[c];
mid = new int[d];
int[] fina = new int[a.length];
int f = 0, l = 0, m = 0;
if (isSorted(a) )
return a;
for (int x = 0; x < a.length; x++) {
if (a[x] < prod) {
first[f] = a[x];
f++;
} else if (a[x] > prod) {
last[l] = a[x];
l++;
} else if (a[x] == prod) {
mid[m] = a[x];
m++;
}
}
if (m == a.length)
return a;
if (1 < first.length) {
first = sort(first);
}
if (1 < last.length) {
last = sort(last);
}
for (int x = 0; x < b; x++) {
fina[x] += first[x];
}
for (int x = 0; x < d; x++) {
fina[x + b] = mid[x];
}
for (int x = 0; x < c; x++) {
fina[x + b + d] = last[x];
}
return fina;
}

Feige Fiat Shamir Implementation

I'm implementing the Fiege Fiat Shamir Identification Scheme in Java, and I'm pretty sure that it's fine math-wise. (I've checked many many times) But it never works (when check is called, it is almost always false, even when called with numbers that should work). I've gotten it to work before without sequences, (k value of 1), but now it doesn't work. Help!
public class ZKPTimeTrials {
public static int gcd(int p, int q) {
if (q == 0) return p;
else return gcd(q, p % q);
}
public static int randomR(int min, int max) {
Random randgen = new Random();
return randgen.nextInt((max - min) + 1) + min;
}
public static int getRandomCoprime(int n) {
int result = n;
while (gcd(n, result) != 1) {
result = randomR(2, n-1);
}
return result;
}
public static int[] makeSi(int k, int n) {
int[] result = new int[k];
for(int i = 0; i < result.length; i++) {
result[i] = getRandomCoprime(n);
}
return result;
}
public static int[] makeVi(int[] si, int n) {
int[] result = new int[si.length];
for(int i = 0; i < result.length; i++) {
result[i] = (si[i] * si[i]) % n;
}
return result;
}
public static int[] makeEi(int k) {
int[] result = new int[k];
for(int i = 0; i < k; i++) {
result[i] = randomR(0, 1);
}
return result;
}
public static int makeY(int r, int[] ei, int[] si, int n) {
int result = r;
for(int i = 0; i < si.length; i++) {
result *= (int) Math.pow(si[i], ei[i]);
}
return result % n;
}
public static boolean check(int n, int x, int y, int[] ei, int[] vi) {
int signBit = ZKPTimeTrials.randomR(0, 1);
if(signBit == 0) {
signBit = -1;
}
int shouldY = x * signBit;
for(int i = 0; i < vi.length; i++) {
shouldY *= (int) Math.pow(vi[i], ei[i]);
}
return ((y * y) % n) == shouldY % n;
}
public static void main(String args[]) {
int n = 71 * 7;
int t = 50;
int k = 10;
int[] si = makeSi(k, n);
int[] vi = makeVi(si, n);
int r = randomR(2, n-1);
int ei[] = makeEi(k);
int s = randomR(0, 1);
if(s == 0) {
s = -1;
}
int x = (s * r * r) % n;
int y = makeY(r, ei, si, n);
for(int i = 0; i < si.length; i++) System.out.print(ei[i] + " ");
System.out.println();
for(int i = 0; i < si.length; i++) System.out.print(si[i] + " ");
System.out.println(check(n, x, y, ei, vi));
}
}
The first problem is an integer overflow in makeY and check: In both functions 'result' is very likely to overflow, because you build the product first and reduce modulo n afterwards. Try to reduce mod n after every multiplication to keep 'result' small.
For example in makeY, write:
int result = r % n;
for (int i = 0; i < si.length; i++) {
if (ei[i] == 1)
result = (result * si[i]) % n;
}
return result;
(I also removed Math.pow() to make it more readable and efficient, but this was not an error.)
The second problem is the logic of your check function: The signBit variable is not needed, but instead you should check if y*y is equal to shouldY or -shouldY.
public static boolean check(int n, int x, int y, int[] ei, int[] vi) {
int shouldY = x % n;
for (int i = 0; i < vi.length; i++) {
if (ei[i] == 1)
shouldY = (shouldY * vi[i]) % n;
}
return (y*y - shouldY) % n == 0 || (y*y + shouldY) % n == 0;
}
With these small corrections i managed to get your code running. Hope it helps...

Categories