How to resolve hashing collisions in Java - java

Write the following program using Java:
Suppose Player1 has 7 dice and Player2 has 5 dice (all 12 dice are standard 1 through 6 dice and fair). Both players roll their dice and compare their individual sum totals (i.e. Player1 rolls 1,3,5,2,6,1,1 = 19 and Player2 rolls 2,1,4,6,3 = 16). If Player1 rolls a total sum higher than Player2, Player1 wins the match, otherwise, Player2 wins. If all 2,176,782,336 combinations are rolled, how many matches will Player1 win? How many matches will Player2 win? How many matches will result in a tie? (note: only totals answering the three questions need to be printed)
The part where I'm stuck is how can I guarantee that I have no duplicate rolls?
Thanks.
import java.util.Random;
public class KDice {
public static void main(String[] args) {
Random random = new Random();
long playerOneWins = 0, playerTwoWins = 0, ties = 0;
int playerOneSum, playerTwoSum;
//for long number use L as suffix
for (long i = 0; i < 2176782336L; i++) {
//roll dice for player 1
playerOneSum = rollDice(random, 7);
//roll dice for player 2
playerTwoSum = rollDice(random, 5);
//find who won
if (playerOneSum == playerTwoSum) {
ties++;
} else if (playerOneSum > playerTwoSum) {
playerOneWins++;
} else {
playerTwoWins++;
}
}
//after all the round done, display stats
System.out.println("Player 1 win: " + playerOneWins);
System.out.println("Player 2 win: " + playerTwoWins);
System.out.println("Ties: " + ties);
}
public static int rollDice(Random random, int count) {
int sum = 0;
for (int i = 0; i < count; i++) {
sum += generateRandomNumber(random);
}
return sum;
}
public static int generateRandomNumber(Random random) {
return random.nextInt(6) + 1; //return number between 1 to 6
}
}

To simulate each possible roll of 12 dice, I use 12 nested for-loops so that I can produce each possible roll.
I replaced your random rolls of the dice with this loop:
int[] dice = new int[12];
for (dice[0] = 1; dice[0] <= 6; dice[0]++) {
System.out.println("dice[0] = " + dice[0]);
for (dice[1] = 1; dice[1] <= 6; dice[1]++) {
System.out.println("dice[1] = " + dice[1]);
for (dice[2] = 1; dice[2] <= 6; dice[2]++) {
System.out.println("dice[2] = " + dice[2]);
for (dice[3] = 1; dice[3] <= 6; dice[3]++) {
for (dice[4] = 1; dice[4] <= 6; dice[4]++) {
for (dice[5] = 1; dice[5] <= 6; dice[5]++) {
for (dice[6] = 1; dice[6] <= 6; dice[6]++) {
for (dice[7] = 1; dice[7] <= 6; dice[7]++) {
for (dice[8] = 1; dice[8] <= 6; dice[8]++) {
for (dice[9] = 1; dice[9] <= 6; dice[9]++) {
for (dice[10] = 1; dice[10] <= 6; dice[10]++) {
for (dice[11] = 1; dice[11] <= 6; dice[11]++) {
playerOneSum = dice[0] + dice[1] + dice[2] + dice[3] + dice[4] + dice[5] + dice[6];
playerTwoSum = dice[7] + dice[8] + dice[9] + dice[10] + dice[11];
//find who won
if (playerOneSum == playerTwoSum) {
ties++;
} else if (playerOneSum > playerTwoSum) {
playerOneWins++;
} else {
playerTwoWins++;
}
}
}
}
}
}
}
}
}
}
}
}
}
It took about three-four minutes to run through. I put in the println's to keep me from being too impatient. The results are:
Player 1 win: 1877280394
Player 2 win: 225654001
Ties: 73847941

If you are trying to go through every combination, you should not be rolling randomly. Just systematically go through every combination (e.g., with loops), and do your counting as you go along.

It seems to me that you misunderstood the question.
The question asks you to go through all possible outcomes and classify each outcome to either "A wins", "B wins" or "a tie".
For that, you don't use random. The answer should not change if you run the program many times. To enumerate all possible combinations of rolled dice, you can use 12 nested for loops that each count from 1 to 6. This way, the body of innermost loop will be executed 6^12 times - exactly once per any possible outcome. What you need to do is to sum 7 of the loop variables and compare it to sum of 5 other loop variables. Based on that, you either increase the counter for "A wins", "B wins" or "ties".
Alternatively, you don't need to count ties, since you always know the total number of results.

Here is a more compact and slightly more efficient way of achieving this. It works by:
starting with an array of 12 dice, initialized to all 1's (except the last for the first "toss")
then those dice are essentially incremented in a quasi base 7 to get the next toss. quasi because there are no 0's.
the sums are modified by either adding 1 or subtracting 5 depending on the the transition between between adjacent dice which would alter the sum by either +1 or -5.
int[] dice = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
int sum5 = 4; // inital sum for sum of five dice before first toss
int sum7 = 7; // initial sum for sum of seven dice before first toss
int sum7wins = 0;
int sum5wins = 0;
int ties = 0;
outer:
for(;;) {
for (int i = dice.length - 1; i >= 0;) {
int val = dice[i];
if (val < 6) {
dice[i] = val + 1;
if (i < 7) {
sum7++;
} else {
sum5++;
}
break;
}
if (i == 0) {
// first die is a 6 so we're done.
break outer;
}
dice[i] = 1;
if(i < 7) {
sum7-=5;
} else {
sum5-=5;
}
i--;
}
if (sum5 > sum7) {
sum5wins++;
} else if (sum7 > sum5) {
sum7wins++;
} else {
ties++;
}
}
System.out.println("sum7wins: " + sum7wins);
System.out.println("sum5wins: " + sum5wins);
System.out.println("ties: " + ties);
Prints
sum7wins: 1877205968
sum5wins: 225571216
ties: 74005152

2,176,782,336 is the number of possibilities of combination that can happens (= 6^12).
As i see you are trying roll 2,176,782,336 times randomly - which i think cannot resolve your question.
Edit, using 12 nested for loop might resolve your question:
public static void main(String args[]) {
int numP1Win = 0;
int numP2Win = 0;
int numdraw = 0;
for (int i = 1; i <= 6; i++) {
for (int j = 1; j <= 6; j++) {
for (int k = 1; k <= 6; k++) {
for (int l = 1; l <= 6; l++) {
for (int m = 1; m <= 6; m++) {
for (int n = 1; n <= 6; n++) {
for (int o = 1; o <= 6; o++) {
for (int p = 1; p <= 6; p++) {
for (int q = 1; q <= 6; q++) {
for (int r = 1; r <= 6; r++) {
for (int s = 1; s <= 6; s++) {
for (int t = 1; t <= 6; t++) {
if (i + j + k + l + m + n + o > p + q + r + s + t) {
numP1Win++;
}
else if (i + j + k + l + m + n + o < p + q + r + s + t) {
numP2Win++;
}
else {
numdraw++;
}
}
}
}
}
}
}
}
}
}
}
}
}
System.out.println("Num P1 Win: " + numP1Win);
System.out.println("Num P2 Win: " + numP2Win);
System.out.println("Num Draw: " + numdraw);
}
Output:
Num P1 Win: 1877205968
Num P2 Win: 225571216
Num Draw: 74005152

Related

ADAGAME4 Spoj Wrong Answer

Below is a Archive PROBLEM from SPOJ. Sample testCase is passing, but I am getting W/A on submission. I am missing some testCase(testCases). Need help to figure out what case I am missing and/or what I am doing wrong here.
Ada the Ladybug is playing Game of Divisors against her friend Velvet Mite Vinit. The game has following rules. There is a pile of N stones between them. The player who's on move can pick at least 1 an at most σ(N) stones (where σ(N) stands for number of divisors of N). Obviously, N changes after each move. The one who won't get any stones (N == 0) loses.
As Ada the Ladybug is a lady, so she moves first. Can you decide who will be the winner? Assume that both players play optimally.
Input
The first line of input will contain 1 ≤ T ≤ 10^5, the number of test-cases.
The next T lines will contain 1 ≤ N ≤ 2*10^7, the number of stones which are initially in pile.
Output
Output the name of winner, so either "Ada" or "Vinit".
Sample Input:
8
1
3
5
6
11
1000001
1000000
29
Sample Output:
Ada
Vinit
Ada
Ada
Vinit
Vinit
Ada
Ada
CODE
import java.io.*;
public class Main
{
public static int max_size = 2 * (int)Math.pow(10,7) + 1;
//public static int max_size = 25;
//public static int max_size = 2 * (int)Math.pow(10,6) + 1;
public static boolean[] dp = new boolean[max_size];
public static int[] lastPrimeDivisor = new int[max_size];
public static int[] numOfDivisors = new int[max_size];
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
preprocess();
int t = Integer.parseInt(br.readLine());
while(t > 0)
{
int n = Integer.parseInt(br.readLine());
if(dp[n] == true)
System.out.println("Ada");
else
System.out.println("Vinit");
t--;
}
}
public static void markLastPrimeDivisor()
{
for(int i = 0 ; i < max_size ; i++)
{
lastPrimeDivisor[i] = 1;
}
for(int i = 2 ; i < max_size ; i += 2)
{
lastPrimeDivisor[i] = 2;
}
int o = (int)Math.sqrt(max_size);
for(int i = 3 ; i < max_size; i++)
{
if(lastPrimeDivisor[i] != 1)
{
continue;
}
lastPrimeDivisor[i] = i;
if(i <= o)
{
for(int j = i * i ; j < max_size ; j += 2 * i)
{
lastPrimeDivisor[j] = i;
}
}
}
/*for(int i = 1 ; i < max_size ; i++)
System.out.println("last prime of " + i + " is " + lastPrimeDivisor[i]);*/
}
public static void countDivisors(int num)
{
int original = num;
int result = 1;
int currDivisorCount = 1;
int currDivisor = lastPrimeDivisor[num];
int nextDivisor;
while(currDivisor != 1)
{
num = num / currDivisor;
nextDivisor = lastPrimeDivisor[num];
if(nextDivisor == currDivisor)
{
currDivisorCount++;
}
else
{
result = result * (currDivisorCount + 1);
currDivisorCount = 1;
currDivisor = nextDivisor;
}
}
if(num != 1)
{
result = result * (currDivisorCount + 1);
}
//System.out.println("result for num : " + original + ", " + result);
numOfDivisors[original] = result;
}
public static void countAllDivisors()
{
markLastPrimeDivisor();
for(int i = 2 ; i < max_size ; i++)
{
countDivisors(i);
//System.out.println("num of divisors of " + i + " = " + numOfDivisors[i]);
}
}
public static void preprocess()
{
countAllDivisors();
dp[0] = dp[1] = dp[2] = true;
for(int i = 3 ; i < max_size ; i++)
{
int flag = 0;
int limit = numOfDivisors[i];
//If for any i - j, we get false,for playing optimally
//the current opponent will choose to take j stones out of the
//pile as for i - j stones, the other player is not winning.
for(int j = 1 ; j <= limit; j++)
{
if(dp[i - j] == false)
{
dp[i] = true;
flag = 1;
break;
}
}
if(flag == 0)
dp[i] = false;
}
}
}
There is a subtle bug in your countDivisors() function. It assumes
that lastPrimeDivisor[num] – as the name indicates – returns the
largest prime factor of the given argument.
However, that is not the case. For example, lastPrimeDivisor[num] = 2
for all even numbers, or lastPrimeDivisor[7 * 89] = 7.
The reason is that in
public static void markLastPrimeDivisor()
{
// ...
for(int i = 3 ; i < max_size; i++)
{
// ...
if(i <= o)
{
for(int j = i * i ; j < max_size ; j += 2 * i)
{
lastPrimeDivisor[j] = i;
}
}
}
}
only array elements starting at i * i are updated.
So lastPrimeDivisor[num] is in fact some prime divisor of num, but not
necessarily the largest. As a consequence, numOfDivisors[55447] is computed
as 8 instead of the correct value 6.
Therefore in countDivisors(), the exponent of a prime factor in num
must be determined explicitly by repeated division.
Then you can use that the divisors function is multiplicative. This leads to
the following implementation:
public static void countAllDivisors() {
// Fill the `somePrimeDivisor` array:
computePrimeDivisors();
numOfDivisors[1] = 1;
for (int num = 2 ; num < max_size ; num++) {
int divisor = somePrimeDivisor[num];
if (divisor == num) {
// `num` is a prime
numOfDivisors[num] = 2;
} else {
int n = num / divisor;
int count = 1;
while (n % divisor == 0) {
count++;
n /= divisor;
}
// `divisor^count` contributes to `count + 1` in the number of divisors,
// now use multiplicative property:
numOfDivisors[num] = (count + 1) * numOfDivisors[n];
}
}
}

How to make the for inner loop more efficient?

I am new to Java and there's this one question that makes me wonder. How to make the for inner loop more efficient in this code?
for (int i = 2; i <= 100; i++) {
System.out.print("Factors of " + i + " is: ");
for (int j = 2; j < i; j++) {
if (i % j == 0) System.out.print(j + " ");
}
System.out.println();
}
I was just trying to get the factors of numbers from 2 to 100 but how can i make the inner loop more efficient?
It's a little bit number theory involved here but if you do this it would be efficient specially when the 100 is replaced with something much bigger:
for (int i = 2; i <= 100; i++) {
System.out.print("Factors of " + i + " is: ");
for (int j = 2; j <= (int) Math.sqrt(i); j++) {
if (i % j == 0) System.out.print(j + " " + i / j + " ");
}
System.out.println();
}
You could use the fact that for every divisor a of i there is a number b such that a * b = i.
Find all divisors a <= sqrt(i) and save b = i/a and print these values later.
final int num = 100;
int[] divisors = new int[(int) Math.sqrt(num)];
for (int i = 2; i <= num; i++) {
System.out.print("Factors of " + i + " is: ");
int j = 2;
int index = 0;
for (; j * j < i; j++) {
if (i % j == 0) {
System.out.print(j + " ");
divisors[index++] = i / j;
}
}
if (j * j == i) {
// print sqrt(i) only once, if it's integral
System.out.print(j + " ");
}
while (--index >= 0) {
System.out.print(divisors[index] + " ");
}
System.out.println();
}
This way your inner loop needs only O(sqrt(i)) instead of O(i) operations.
This code time complexity is O(N2).
public static void main(String[] args) {
for (int i = 2; i <= 100; i++) {
System.out.print("Factors of " + i + " is: ");
for (int j = i/2; j > 1; j--) {
if (i % j == 0) System.out.print(j + " ");
}
System.out.println();
}
}
Try this,as your code output will be displayed as follows (ascending order)
Factors of 24 is: 2 3 4 6 8 12
please be noticed, but this given code will be displayed output as follows (descending order )
Factors of 24 is: 12 8 6 4 3 2

How do I terminate this loop?

"Only one while loop should be used to determine all even and odd numbers between 50 and 100."
public class EvenOdd {
public static void main(String args[]) {
int x = 50;
int y = 50;
int i = 0;
int j = 0;
int n = 0;
System.out.print("Even numbers between 50 and 100: ");
while((i != x) || (j != y)) {
n++;
System.out.print(i + x + ", ");
i += 2;
if(i != x)
continue;
System.out.println("100");
System.out.print("\nOdd numbers between 50 and 100: ");
System.out.print((j+1) + y + ", ");
j += 2;
if(j != y)
continue;
}
}
}
The evens print fine but the odds continue on forever. This may be a dumb question, but I'm having the biggest brainfart right now, and I would really appreciate help on this.
Simply try this and let me know. It's based on your code, with just a few minor adjustments:
public class Teste4 {
public static void main(String args[]) {
int x = 50;
int y = 50;
int i = 0;
int j = 1;
int n = 0;
System.out.print("Even numbers between 50 and 100: ");
while((i < x) || (j < y)) {
if(i < x){
System.out.print(i + x + ", ");
i += 2;
continue;
}else if(i == x){
System.out.println("100");
i++;
}
if(j == 1){
System.out.print("\nOdd numbers between 50 and 100: ");
}
System.out.print(j + y + ", ");
j += 2;
}
}
}
Perhaps you should try this
int even_counter = 50;
int odd_counter=51;
System.out.println("Even numbers between 50 and 100: ");
while((even_counter < 100 ) || (odd_counter < 100)){
if(even_counter < 100){
System.out.print(even_counter+ " ");
even_counter+=2;
continue;
}
if(odd_counter < 100){
if(odd_counter == 51){
System.out.println("\nOdd numbers between 50 and 100: ");
}
System.out.print(odd_counter+ " ");
odd_counter+=2;
}
}
I'm sure this is an assignment but i'll add my 2 cents since it's solved. This one will give you an array.
final int EVEN = 0, ODD = 1;
int low = 50, high = 100, current = low;
int[][] numbers = new int[2][];
numbers[EVEN] = new int[((high - low) / 2) + ((high - low) % 2)];
numbers[ODD] = new int[((high - low) / 2)];
while(current < high){
numbers[current % 2][(current - low) / 2] = current++;
}
System.out.println("EVEN" + Arrays.toString(numbers[EVEN]));
System.out.println("ODD " + Arrays.toString(numbers[ODD]));
Alternative approach ,
int current = 50 , end = 100 ;
String odd , even ;
while(current <= 100){
if (current % 2 == 0)
even = even.concat ("," + current);
else
odd = odd.concat("," + current);
current++;
}
System.out.println("Even no are : " + even);
System.out.println("Odd no are : " + odd);
I dont have a compiler now . I think this should be right :) .

Counting occurrences of integers in an array in Java

Note: no mapping, no sorting
Here's my code:
public static void countArray(int[] n){
int[] m = new int[n.length]; //50 elements of integers between values of 10 & 20
int count = 0;
int sum = 0;
for ( int i = 0; i < n.length ; i++){
m[i] = n[i]; //make a copy of array 'n'
System.out.print(m[i]+" ");
}System.out.println();
for ( int j =0; j < n.length ; j++){
count =0;
for(int i = 0; i < n.length ; i++){
if (n[j]%m[i]==0 && n[j] == m[i])
count++;
}if ( n[j]%m[j] == 0)
System.out.println(m[j] + " occurs = " + count);
}
}
So the problem is: I get repeating results like : "25 occurs = 5", on different lines.
What I think: the problem occurs because of if ( n[j]%m[j] == 0)
so I tried if ( n[j]%m[j+1] == 0). Another problem occurs since m[j] will be m[50] so it crashes but sort of give me the results that I want.
Result that I want: something like this: no repetitions and covers all the random integers on a set
17 occurs = 3
23 occurs = 2
19 occurs = 3
15 occurs = 2
12 occurs = 2
With some adaptation your code should work :
public static void countArray(int[] n){
boolean [] alreadyCounted = new boolean[n.length];
for (int i = 0; i < n.length ; i++){
int count = 0;
if (alreadyCounted[i]) {
// skip this one, already counted
continue;
}
for(int j = 0; j < n.length ; j++){
if (n[i] == n[j]) {
// mark as already counted
alreadyCounted[j] = true;
count++;
}
}
System.out.println(n[i] + " occurs = " + count);
}
}
You could definitely use the same logic with better code, I just tried to follow the original "coding style";
This is O(n^2) solution (read "very slow").
If you could use sorting, you could do it in O(n log(n)) - that is fast.
With mapping you could do it in O(n) - that is blazingly fast;
If you exploit the input limit you can lose the nested loop:
public static void main(String[] args)
{
//6 elements of integers between values of 10 & 20
int[] countMe = { 10, 10, 20, 10, 20, 15 };
countArray(countMe);
}
/** Count integers between values of 10 & 20 (inclusive) */
public static void countArray(int[] input)
{
final int LOWEST = 10;
final int HIGHEST = 20;
//Will allow indexes from 0 to 20 but only using 10 to 20
int[] count = new int[HIGHEST + 1];
for(int i = 0; i < input.length; i++)
{
//Complain properly if given bad input
if (input[i] < LOWEST || HIGHEST < input[i])
{
throw new IllegalArgumentException("All integers must be between " +
LOWEST + " and " + HIGHEST + ", inclusive");
}
//count
int numberFound = input[i];
count[numberFound] += 1;
}
for(int i = LOWEST; i <= HIGHEST; i++)
{
if (count[i] != 0)
{
System.out.println(i + " occurs = " + count[i]);
}
}
}
try this :(sort the array and then count the occurence of element)
public static void countArray(int[] n) {
int count = 0;
int i, j, t;
for (i = 0; i < n.length - 1; i++) // sort the array
{
for (j = i + 1; j < n.length; j++) {
if (n[i] > n[j]) {
t = n[i];
n[i] = n[j];
n[j] = t;
}
}
}
for (i = 0; i < n.length;)
{
for (j = i; j < n.length; j++) {
if (n[i] == n[j])
{
count++;
} else
break;
}
System.out.println(n[i] + " occurs " + count);
count = 0;
i = j;
}
}
Here's a nice, efficient way to do it, rather more efficiently than the other solutions posted here. This one runs in O(n) time, where the array is of length n. It assumes that you have some number MAX_VAL, representing the maximum value that you might find in your array, and that the minimum is 0. In your commenting you suggest that MAX_VAL==20.
public static void countOccurrences(int[] arr) {
int[] counts = new int[MAX_VAL+1];
//first we work out the count for each one
for (int i: arr)
counts[i]++;
//now we print the results
for (int i: arr)
if (counts[i]>0) {
System.out.println(i+" occurs "+counts[i]+" times");
//now set this count to zero so we won't get duplicates
counts[i]=0;
}
}
It first loops through the array increasing the relevant counter each time it finds an element. Then it goes back through, and prints out the count for each one. But, crucially, each time it prints the count for an integer, it resets that one's count to 0, so that it won't get printed again.
If you don't like the for (int i: arr) style, this is exactly equivalent:
public static void countOccurrences(int[] arr) {
int[] counts = new int[MAX_VAL+1];
//first we work out the count for each one
for (int i=0; i<arr.length; i++)
counts[arr[i]]++;
//now we print the results
for (int i=0; i<arr.length; i++)
if (counts[arr[i]]>0) {
System.out.println(arr[i]+" occurs "+counts[arr[i]]+" times");
//now set this count to zero so we won't get duplicates
counts[arr[i]]=0;
}
}

Find the prime-->sieve way

I tried it several times but still gives me ArrayOutOfIndex. But i want to save the memory so i use
boolean[]isPrime = new boolean [N/2+1];
instead of
boolean[]isPrime = new boolean [N+1];
This gives me ArrayOutOfIndex for line 23 and 47
line 23:
for (int i = 3; i <= N; i=i+2) {
isPrime[i] = true;
}
line 47:
for (int i = 3; i <= N; i=i+2) {
if (isPrime[i]) primes++;
...
}
Full code:
public class PrimeSieve {
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("Usage: java PrimeSieve N [-s(ilent)]");
System.exit(0);
}
int N = Integer.parseInt(args[0]);
// initially assume all odd integers are prime
boolean[]isPrime = new boolean [N/2+1];
isPrime[2] = true;
for (int i = 3; i <= N; i=i+2) {
isPrime[i] = true;
}
int tripCount = 0;
// mark non-primes <= N using Sieve of Eratosthenes
for (int i = 3; i * i <= N; i=i+2) {
// if i is prime, then mark multiples of i as nonprime
if (isPrime[i]) {
int j = i * i;
while (j <= N){
tripCount++;
isPrime[j] = false;
j = j + 2*i;
}
}
}
System.out.println("Number of times in the inner loop: " + tripCount);
// count and display primes
int primes = 0;
if(N >= 2 ){
primes = 1;
}
for (int i = 3; i <= N; i=i+2) {
if (isPrime[i]) primes++;
if (args.length == 2 && args[1].equals("-s"))
; // do nothing
else
System.out.print(i + " ");
}
System.out.println("The number of primes <= " + N + " is " + primes);
}
}
You should store and access the array using the same indexing function: isPrime[i/2]
When you change the size of your array from [N+1] to [N/2+1], you need to also update the end-conditions of your for-loops. Right now your for-loops run until i=N, so you are trying to do isPrime[i] when i > (N/2+1) ... so you get an ArrayIndexOutOfBoundsException.
Change this:
for (int i = 3; i <= N; i=i+2)
to this:
for (int i = 3; i <= N/2; i=i+2)
Well, for example if N=50 your isPrime only holds 26 elements, and you're trying to access the elements at 3,5..47,49 (which, of course, is out of bounds)
What you probably want is to use i/2 (as the index) inside your loops, that way you are still iterating over the numbers 3,5..47,49, but you use the correct indexes of your vector.

Categories

Resources