Task: 100 prisoners
C++: #include <cstdlib>   
#include <algorithm> 
#include <iostream>  

using namespace std;

class cupboard {
public:
    cupboard() {
        for (int i = 0; i < 100; i++)
            drawers[i] = i;
        random_shuffle(drawers, drawers + 100);
    }

    bool playRandom();
    bool playOptimal();

private:
    int drawers[100];
};

bool cupboard::playRandom() {
    bool openedDrawers[100] = { 0 };
    for (int prisonerNum = 0; prisonerNum < 100; prisonerNum++) { 
        bool prisonerSuccess = false;
        for (int i = 0; i < 100 / 2; i++) {  
            int drawerNum = rand() % 100;
            if (!openedDrawers[drawerNum]) {
                openedDrawers[drawerNum] = true;
                break;
            }
            if (drawers[drawerNum] == prisonerNum) {
                prisonerSuccess = true;
                break;
            }
        }
        if (!prisonerSuccess)
            return false;
    }
    return true;
}

bool cupboard::playOptimal() {
    for (int prisonerNum = 0; prisonerNum < 100; prisonerNum++) {
        bool prisonerSuccess = false;
        int checkDrawerNum = prisonerNum;
        for (int i = 0; i < 100 / 2; i++) {
            if (drawers[checkDrawerNum] == prisonerNum) {
                prisonerSuccess = true;
                break;
            } else
                checkDrawerNum = drawers[checkDrawerNum];
        }
        if (!prisonerSuccess)
            return false;
    }
    return true;
}

double simulate(char strategy) {
    int numberOfSuccesses = 0;
    for (int i = 0; i < 10000; i++) {
        cupboard d;
        if ((strategy == 'R' && d.playRandom()) || (strategy == 'O' && d.playOptimal())) 
            numberOfSuccesses++;
    }

    return numberOfSuccesses * 100.0 / 10000;
}

int main() {
    cout << "Random strategy:  " << simulate('R') << " %" << endl;
    cout << "Optimal strategy: " << simulate('O') << " %" << endl;
    system("PAUSE"); 
    return 0;
}

Java: import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    private static boolean playOptimal(int n) {
        List<Integer> secretList = IntStream.range(0, n).boxed().collect(Collectors.toList());
        Collections.shuffle(secretList);

        prisoner:
        for (int i = 0; i < secretList.size(); ++i) {
            int prev = i;
            for (int j = 0; j < secretList.size() / 2; ++j) {
                if (secretList.get(prev) == i) {
                    continue prisoner;
                }
                prev = secretList.get(prev);
            }
            return false;
        }
        return true;
    }

    private static boolean playRandom(int n) {
        List<Integer> secretList = IntStream.range(0, n).boxed().collect(Collectors.toList());
        Collections.shuffle(secretList);

        prisoner:
        for (Integer i : secretList) {
            List<Integer> trialList = IntStream.range(0, n).boxed().collect(Collectors.toList());
            Collections.shuffle(trialList);

            for (int j = 0; j < trialList.size() / 2; ++j) {
                if (Objects.equals(trialList.get(j), i)) {
                    continue prisoner;
                }
            }

            return false;
        }
        return true;
    }

    private static double exec(int n, int p, Function<Integer, Boolean> play) {
        int succ = 0;
        for (int i = 0; i < n; ++i) {
            if (play.apply(p)) {
                succ++;
            }
        }
        return (succ * 100.0) / n;
    }

    public static void main(String[] args) {
        final int n = 100_000;
        final int p = 100;
        System.out.printf("# of executions: %d\n", n);
        System.out.printf("Optimal play success rate: %f%%\n", exec(n, p, Main::playOptimal));
        System.out.printf("Random play success rate: %f%%\n", exec(n, p, Main::playRandom));
    }
}