find probability of n people in a class of x share the same birthday using monte carlo simulation in java

176 views Asked by At

As the problem states, i must use monte carlo(randomness) to solve the question given. I am running the simulation 1,000,000 times.

import java.util.*;

public class MonteCarlo {
    public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
       System.out.println("Please enter size of the class: ");
       int classSize = sc.nextInt();
       System.out.println("Please enter the amount of people who share the same birthday: ");
       int birthPpl = sc.nextInt();
       System.out.println("calculate the probability that "+birthPpl+" people share the same Birthday in a class size of "+classSize);
      
       sc.close();
       
       int birthdays [] = new int[classSize];
       int simulations = 0;
       int success=0;
       for(int i=0; i<1000000; i++){
            simulations++;
            if(Collision(birthdays)>=birthPpl){
                success++;
            }
       }
       System.out.println(success+" "+simulations);
       System.out.println("Answer: "+ (success*100)/simulations + "%");
    }

    public static int Collision(int birthday[]){
        Random rand = new Random();
        for(int i=1; i<birthday.length; i++){
            birthday[i]= rand.nextInt(365);
        }

        int count = 0;
        for(int i=0; i<birthday.length; i++){
            for(int j= i+1; j<birthday.length; j++){
                
                if(birthday[i]==birthday[j]){
                    count++;
                }
            }
        }
        return count;
    }
}

As per a couple of psuedo code solutions i have seen online i have tried looping through the size of the class x and inserting in a random birthday. then comparing birthdays , reducing the birthdays i look through by 1 each time. I then check the number of collisions against the amount sof ppl who should a birthday , if it is greater or equal to it than i increase the count. i have been given sample imput 20 and 2 which should give 41 % but my program gives eithe 7 or 8 %

What's the problem, and how can it be fixed?

2

There are 2 answers

0
WJS On

You could also make use the Random and HashMap classes. Map.merge will take the key, a birthday in this case, then a default value of 1, and continues to add 1 to the existing value which is returned and compared to x. Then success is appropriately updated. The Random class provides a variety of methods to return random numbers and is usually preferred over Math.random.

double success = 0;
int tests = 1_000_000;

// instantiate a Random class for selecting the next birthday
Random r = new Random();

// a map to hold the frequency count of same birthdays
Map<Integer,Integer> birthdays = new HashMap<>();


int n = 23;
int x = 2;

for(int i=0; i< tests; i++) {
   for (int j = 0; j < n; j++) {
       if (birthdays.merge(r.nextInt(365), 1, Integer::sum) >= x) {
           success++;
           break;
       }
   }
   // clear the map for the next run
   birthdays.clear();
}

Using System.out.printf facilitates formatting the output.

System.out.printf("probability = %4.1f%%%n", (success/tests) * 100);

prints something like the following:

probability = 50.7%
2
rimvoo On
import java.util.Scanner;

public class Birthday {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); // class size
        int x = sc.nextInt(); // people who share the same birthday
        double tests = 1_000_000;
        double success = 0;


        // fills array of birthdays and breaks out when x amount of people share 
        // a birthday. then we find the % of successes.
        for (int i = 0; i < tests; i++) {
            int[] year = new int[365];

            for (int j = 0; j < n; j++) {
                int birthday = (int) (Math.random() * 365);
                year[birthday]++;
                if (year[birthday] >= x) {
                    success++;
                    break;
                }
            }
        }

        System.out.println(Math.round(success * 100 / tests));
    }
}