Farbstiftspitzen (Simulationen)
Voraussetzung: In einem Etui sind 20 Farbstifte. Alle sind stumpf und müssen gespitzt werden.
Nach folgendem Verfahren werden die Farbstifte nun gespitzt:
- Aufs Mal werden drei Stifte "blind" aus dem Etui genommen (beim ersten solchen "blinden Griff" sind natürlich alle drei stumpf).
- Alle drei Stifte werden gespitzt (die bereits spitzen darunter natürlich nicht).
- Die drei spitzen Stifte werden wieder zurückgelegt.
Die obigen drei Schritte werden so oft wiederholt, bis alle gespitzt sind. Dabei werden oft auch bereits gespitzte Farbstifte "gezogen".
- Schreiben Sie zunächst die Funktion, die drei verschiedene Zufallszahlen im Bereich 0 bis 19 findet.
- Simulieren Sie nun eine solche Spitzaktion und zählen Sie, wie oft herausgegriffen werden muss, bis alle gespitzt sind.
- Simulieren Sie nun 10 000 "Spitzaktionen" mit 20 Stiften und drei Blindgriffen pro Mal und messen Sie dabei
- die durchschnittliche Anzahl Griffe,
- minimale und maximale Anzahl Griffe.
- d) Verallgemeinern Sie die Aufgabe auf n Stifte (n > 2) und m Stifte pro Blindgriff (1 ? m < n).
0 Kommentare
5 Lösung(en)
package eu.gressly.hw.simulation.spitzaktion;
import java.util.Random;
public class FarbstiftSpitzAktion {
public static void main(String[] args) {
new FarbstiftSpitzAktion().start(20, 3, 10000);
}
Random randomGenerator = new Random();
void start(int totalStifte, int stifteAufsMal, int spitzAktionen) {
int versuchsNummer = 0;
int totalVersucheAllerSpitzaktionen = 0;
int kuerzesteSpitzaktion = -1;
int laengsteSpitzaktion = 0;
while (versuchsNummer < spitzAktionen) {
boolean[] neuesEtui = new boolean[totalStifte];
int aktGriffe = spitzaktion(neuesEtui, stifteAufsMal);
totalVersucheAllerSpitzaktionen = totalVersucheAllerSpitzaktionen
+ aktGriffe;
if (-1 == kuerzesteSpitzaktion) {
kuerzesteSpitzaktion = aktGriffe;
} else if (aktGriffe < kuerzesteSpitzaktion) {
kuerzesteSpitzaktion = aktGriffe;
}
if (aktGriffe > laengsteSpitzaktion) {
laengsteSpitzaktion = aktGriffe;
}
versuchsNummer = versuchsNummer + 1;
}
System.out.println("Benoetige durchschnittlich: "
+ ((double) totalVersucheAllerSpitzaktionen / spitzAktionen)
+ " Versuche");
System.out.println("Min:" + kuerzesteSpitzaktion);
System.out.println("Max:" + laengsteSpitzaktion);
}
int spitzaktion(boolean[] etui, int aufsMal) {
int versuche = 0;
while (!alleGespitzt(etui)) {
spitzen(etui, aufsMal);
versuche = versuche + 1;
}
return versuche;
}
boolean alleGespitzt(boolean[] etui) {
for (boolean spitz : etui) {
if (!spitz) {
return false;
}
}
return true;
}
void spitzen(boolean[] etui, int aufsMal) {
// wähle "aufsMal" Zufallszahlen aus [0..etui.length - 1]
// int[] samples = pickSample(etui.length, aufsMal);
shuffle(aufsMal, etui.length);
// spitze diese, egal, ob spitz oder stumpf
int idx = 0;
while (idx < aufsMal) {
etui[INDIZES_ARRAY[idx]] = true; // spitz
idx = idx + 1;
}
}
/************************************************
* Sampling: n Zufallszahlen aus den ersten N indizes {0. ... N-1}
*/
int[] INDIZES_ARRAY; // enhält 0, 1, 2, ... N-1
void initIndizes(int len) {
INDIZES_ARRAY = new int[len];
int actPos = 0;
while (actPos < len) {
INDIZES_ARRAY[actPos] = actPos;
actPos = actPos + 1;
}
}
// zahl zwischen min und max (beide inklusive)
int rndPos(int min, int max) {
return ((int) (randomGenerator.nextDouble() * (max - min + 1))) + min;
}
void swap(int a, int b) {
int tmp = INDIZES_ARRAY[a];
INDIZES_ARRAY[a] = INDIZES_ARRAY[b];
INDIZES_ARRAY[b] = tmp;
}
// nach "shuffle" sind die ersten n aus N gemischt.
void shuffle(int n, int N) {
if (null == INDIZES_ARRAY || INDIZES_ARRAY.length != N) {
initIndizes(N);
}
int inPos = 0;
while (inPos <= n - 1) {
int rndPos = rndPos(inPos, N - 1);
swap(inPos, rndPos);
inPos = inPos + 1;
}
}
/*
* Altenativ, falls die Sample Anzahl hoch im Verhältnis zur Gesamtzahl. //
* see: http://www.javamex.com/tutorials/random_numbers/random_sample.shtml
* int[] pickSample(int left, int samplesNeeded) { int[] result = new
* int[samplesNeeded]; int pickedAlready = 0; int act = 0; while
* (samplesNeeded > 0) { int rand = randomGenerator.nextInt(left); if (rand
* < samplesNeeded) { result[pickedAlready] =act; pickedAlready =
* pickedAlready + 1; samplesNeeded = samplesNeeded - 1; } left = left - 1;
* act = act + 1; } return result; }
*/
} // end of class FarbstiftSpitzAktion
#Farbstiftspitzen
import random
def spitzaktion(Etui, stifteAufsMal):
zaehler =0
while (False in Etui):
zaehler +=1
for i in range(stifteAufsMal):
zug = random.randint(0, len(Etui)-1)
Etui[zug] = True
return zaehler
def farbstiftSpitzAktion(totalStifte, stifteAufsMal,spitzAktionen):
versuchsNummer= 0
totalVersucheAllerSpitzaktionen=0
kuerzesteSpitzaktion=1000000
laengsteSpitzaktion=0
while(versuchsNummer < spitzAktionen):
neuesEtui = [False]*totalStifte
aktGriffe = spitzaktion(neuesEtui, stifteAufsMal)
if (aktGriffe < kuerzesteSpitzaktion):
kuerzesteSpitzaktion = aktGriffe
if (aktGriffe > laengsteSpitzaktion):
laengsteSpitzaktion = aktGriffe
totalVersucheAllerSpitzaktionen += aktGriffe
versuchsNummer +=1
print 'Total Anzahl Spitzaktionen (3 Stifte): '+str(totalVersucheAllerSpitzaktionen)
print 'Kuerzeste Spitzaktion: '+str(kuerzesteSpitzaktion)
print 'Laengste Spitzaktion: '+str(laengsteSpitzaktion)
# 20 Stifte, 3 werden gezogen, 10000 Wiederholungen
farbstiftSpitzAktion(20,3,100000)
const NUMBER_OF_CRAYONS = 20,
NUMBER_OF_TAKES = 3;
Array.prototype.max = function() { return Math.max.apply(null, this); }
Array.prototype.min = function() { return Math.min.apply(null, this); }
Array.prototype.avg = function() { return this.reduce((a, b) => a + b, 0) / this.length; }
let pencilCase = [];
// buntstifte initialisieren
// false = ungespitzt, true = angespitzt
pencilCase.reset = function() {
for (let i = 0; i < NUMBER_OF_CRAYONS; i++)
pencilCase[i] = false;
}
// anspitz-prozedur
function sharpenSome() {
// zufällige stifte wählen
let rndCrayons = [];
while (rndCrayons.length < NUMBER_OF_TAKES) {
let x = Math.floor(Math.random() * NUMBER_OF_CRAYONS);
if (rndCrayons.indexOf(x) == -1) rndCrayons.push(x);
}
// buntstifte spitzen
// könnte stark verkürzt werden, ich lass es aber mal so, der
// lesbarkeit zuliebe
for (let i = 0; i < rndCrayons.length; i++) {
x = rndCrayons[i];
if (pencilCase[x] == false) pencilCase[x] = true;
}
}
// spitzen, bis alle spitz sind
function sharpenAll() {
let counter = 0;
pencilCase.reset();
while (pencilCase.indexOf(false) != -1) {
sharpenSome();
counter++;
}
return counter;
}
// testreihe
let records = [];
for (let i = 1; i <= 1e4; i++) records.push(sharpenAll());
// ausgabe
console.log(`Durchschnittliche Anzahl der Durchgänge: ${records.avg().toFixed(1)}`);
console.log(`Kleinste Anzahl der Durchgänge: ${records.min()}`);
console.log(`Höchste Anzahl der Durchgänge: ${records.max()}`);
// lissalanda@gmx.at
Lösung von: Lisa Salander (Heidi-Klum-Gymnasium Bottrop)
// C++ 20 | VS-2022
#include <iostream>
#include <random>
#include <array>
#include <algorithm>
#include <tuple>
#include <numeric>
constexpr size_t NUM_OF_PENCILS{ 20 };
constexpr size_t NUM_OF_PICK_OUT{ 3 };
constexpr size_t NUM_OF_TESTS{ 100'000 };
inline const auto get_attempts() {
std::array<bool, NUM_OF_PENCILS>arr{};
auto counter{ 0 };
while (!std::all_of(arr.begin(), arr.end(), [](auto x) {return x == true; })) {
++counter;
std::shuffle(arr.begin(), arr.end(), std::random_device());
for (auto it{ arr.begin() }; it < arr.begin() + NUM_OF_PICK_OUT; ++it) *it = true;
}
return counter;
}
inline const auto get_test_results() {
size_t min{ INT_MAX };
size_t max{ 0 };
size_t sum{ 0 };
for (size_t i{ 0 }; i < NUM_OF_TESTS; ++i) {
const auto res{ get_attempts() };
sum += res;
if (res < min) min = res;
if (res > max) max = res;
}
const double avg{ (double)sum / NUM_OF_TESTS };
return std::make_tuple(min, max, avg);
}
int main() {
const auto& [min, max, avg] = get_test_results(); // C++ 20!
std::cout <<"Minimum: " << min << "\n";
std::cout <<"Maximum: " << max << "\n";
std::cout <<"Mittelwert: " << avg << "\n";
}
Lösung von: Jens Kelm (@JKooP)
// NET 7.x | C# 11.x | VS-2022
const int NUM_OF_PENCILS = 20;
const int NUM_OF_PICK_OUT = 3;
const int NUM_OF_TESTS = 10_000;
var (min, max, avg) = GetTestResults();
Console.WriteLine($"Minimum: {min}\n");
Console.WriteLine($"Maximum: {max}\n");
Console.WriteLine($"Mittelwert: {avg}\n");
int GetAttempts() {
var rnd = new Random();
var lst = new List<bool>(new bool[NUM_OF_PENCILS]);
var counter = 0;
while(!lst.All(x => x)) {
++counter;
lst = lst.OrderBy(x => rnd.Next()).ToList();
for (int i = 0; i < NUM_OF_PICK_OUT; i++)
lst[i] = true;
}
return counter;
}
(int, int, double) GetTestResults() {
var min = int.MaxValue;
var max = 0;
var sum = 0;
for (int i = 0; i < NUM_OF_TESTS; i++) {
var res = GetAttempts();
sum += res;
if (res < min) min = res;
if (res > max) max = res;
}
var avg = (double)sum / NUM_OF_TESTS;
return (min, max, avg);
}
Lösung von: Jens Kelm (@JKooP)
Verifikation/Checksumme:
Bei 10 000 Spitzaktionen, 20 Stiften und 3 Stiften pro "blindem Griff" ergeben sich in etwa die folgenden Zahlen für die Anzahl Griffe:
Mittelwert: 23.05 +/- 0.05
Minimum: 7 (mathematisch), meist 8 oder 9
Maximum: ca. 65 bis 100; mathematisch gibt es keine(!) Obergrenze.
Aktionen
Neue Lösung hinzufügen
Bewertung
Durchschnittliche Bewertung:
Meta
Zeit: | 2 |
Schwierigkeit: | k.A. |
Webcode: | i7ox-fcxf |
Autor: | Stefan Dürrenberger (IDM Studios GmbH) |