乱数の個数を限定する
Posted: 2015年1月19日(月) 02:30
int i, t, t1, t2, s[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}; // 0が15個、1が5個
srand(time(0));
for (i = 0; i < 20; i++)//とりあえず20回繰り返す
{
t1 = rand() % 20; // 交換元
t2 = rand() % 20; // 交換先
if (t1 != t2) { // 同じ場合は意味がないので、この判定をする
// 交換。
t = s[t1];
s[t1] = s[t2];
s[t2] = t;
}
}
確かにそうですが、最初に全部シャッフルしなくても、へにっくす さんが書きました:最初にそのデータを作成しておいて、ランダムを使って交換を行うようにすればよいと思います。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* 0以上max未満の整数をランダムに返す関数 */
int rand_upto(int max) {
/* 必要ならもっといい実装をしてください */
return rand() % max;
}
int main(void) {
#ifndef PUTTERN2
/* 1の数は5個、0が15個 */
int candidates_left = 20; /* 乱数の候補の残り数 */
int candidates[20] = { /* 乱数の候補 */
1, 1, 1, 1, 1,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
};
#else
/* 0が10個、1が7個、2が3個 */
int candidates_left = 20; /* 乱数の候補の残り数 */
int candidates[20] = { /* 乱数の候補 */
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
1, 1, 1, 1, 1,
1, 1,
2, 2, 2
};
#endif
srand((unsigned int)time(NULL));
while (candidates_left > 0) {
int idx = rand_upto(candidates_left--);
int rand_result = candidates[idx];
candidates[idx] = candidates[candidates_left];
/* candidates[candidate_left]はもう利用しないので、交換ではなく1方向のコピーでよい */
/* candidates[candidate_left] = rand_result; */
printf("%d ", rand_result);
}
putchar('\n');
return 0;
}
int main(void)
{
srand(time(0));
const int nPtn= 2;
int Left[nPtn] = { 15, 5 }; //残り個数:0が15個,1が5個
//乱数取得試行回数N=↑のLeft[]の合計
int N = 0;
for( int i=0; i<nPtn; i++ )N+=Left[i];
//N回やる
for( int i=0; i<N; i++ )
{
int result = 0;
int MaxScore = -1;
for( int j=0; j<nPtn; j++ )
{
if( Left[j]<=0 )continue;
int score = rand() % Left[j];
if( MaxScore < score )
{
MaxScore = score;
result = j;
}
}
--Left[result];
//この回の乱数値を出力
std::cout << '[' << i << "] : " << result << std::endl;
}
//
std::cout << "enter to quit" << std::endl;
std::cin.ignore();
return 0;
}
int main(void)
{
srand(time(0));
const int nPtn= 3;
int Left[nPtn] = { 10, 7, 3 }; //残り個数
//乱数取得試行回数N=↑のLeft[]の合計
int N = 0;
for( int i=0; i<nPtn; i++ )N+=Left[i];
//N回乱数
for( int i=0; i<N; i++ )
{
int r = rand() % (N-i);
for( int j=0; j<nPtn; j++ )
{
if( r<Left[j] )
{
--Left[j];
std::cout << '[' << i << "] : " << j << std::endl; //この回の乱数値を出力
break;
}
else
{ r -= Left[j]; }
}
}
//
std::cout << "enter to quit" << std::endl;
std::cin.ignore();
return 0;
}
#include <random>
#include <array>
#include <iostream>
#include <algorithm>
int main()
{
std::random_device seed;
std::mt19937 engine(seed());
// 確率列を定義
std::array<double, 2> probabilities = {
0.75,0.25
};
// 分布オブジェクトを生成
std::discrete_distribution<std::size_t> dist{
probabilities.begin(),
probabilities.end()
};
using Result = std::size_t;
static const size_t NUMBER = 20;
std::array<Result, NUMBER> result;
for (size_t n = 0; n < NUMBER; ++n) {
result[n] = dist(engine);
std::cout << result[n];
}
std::cout << std::endl;
std::cout << "0:" << std::count_if(result.cbegin(), result.cend(), [](Result a){ return a == 0; }) << std::endl;
std::cout << "1:" << std::count_if(result.cbegin(), result.cend(), [](Result a){ return a == 1; }) << std::endl;
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* 配列で表現されたBITのidx番目(0-origin)にvalueを加算する */
void bit_add(int bit[], int bit_size, int idx, int value) {
idx++;
while (idx <= bit_size) {
bit[idx - 1] += value;
idx += idx & (-idx);
}
}
/* 配列で表現されたBITのidx番目(0-origin)までの和を求める。(idx番目を含む) */
int bit_sum(const int bit[], int idx) {
int ret = 0;
if (idx < 0) return 0;
idx++;
while (idx > 0) {
ret += bit[idx - 1];
idx -= idx & (-idx);
}
return ret;
}
/* 0以上max未満の整数をランダムに返す関数 */
int rand_upto(int max) {
/* 必要ならもっといい実装をしてください */
return rand() % max;
}
int main(void) {
#ifndef PUTTERN2
/* 1の数は5個、0が15個 */
const int candidates_num = 2; /* 乱数の候補の種類数 */
const int candidates[2] = {1, 0}; /* 乱数の候補 */
int candidates_left[2] = {5, 15}; /* 各乱数の候補の残り個数 */
int candidates_bit[2]; /* どの乱数の候補が残っているかを管理するBIT (Binary Indexed Tree) */
#else
/* 0が10個、1が7個、2が3個 */
const int candidates_num = 3;
const int candidates[3] = {0, 1, 2};
int candidates_left[3] = {10, 7, 3};
int candidates_bit[3];
#endif
int i;
srand((unsigned int)time(NULL));
/* BITを初期化する */
for (i = 0; i < candidates_num; i++) candidates_bit[i] = 0;
for (i = 0; i < candidates_num; i++) {
if (candidates_left[i] > 0) bit_add(candidates_bit, candidates_num, i, 1);
}
for (;;) {
/* 1個以上残っている乱数の候補の数 */
int left_candidates = bit_sum(candidates_bit, candidates_num - 1);
/* 出す乱数の候補 */
int idx;
/* 二分探索で使用する変数 */
int left, right, mid, random_result_idx;
/* 実際に出た乱数 */
int random_result;
if (left_candidates <= 0) {
/* 出せる乱数が残っていない */
break;
}
/* どの候補を出すかを決定する */
idx = rand_upto(left_candidates);
/* 具体的にそれがどの候補に当たるのかを求める */
left = 0;
random_result_idx = right = candidates_num - 1;
while (left <= right) {
mid = left + (right - left) / 2;
/* そこまでの和がidxを超える最小の添え字を求める */
if (idx < bit_sum(candidates_bit, mid)) {
if (random_result_idx > mid) random_result_idx = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
/* 出た候補の残り数を1減らす */
if((--candidates_left[random_result_idx]) == 0) {
/* 減らした結果その候補が無くなったら、BITからその候補があるという情報を消す */
bit_add(candidates_bit, candidates_num, random_result_idx, -1);
}
/* どの候補かという情報から具体的な候補を求める */
random_result = candidates[random_result_idx];
/* 出た乱数を出力する */
printf("%d ", random_result);
}
putchar('\n');
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* 配列で表現されたBITのidx番目(0-origin)にvalueを加算する */
void bit_add(int bit[], int bit_size, int idx, int value) {
idx++;
while (idx <= bit_size) {
bit[idx - 1] += value;
idx += idx & (-idx);
}
}
/* 配列で表現されたBITのidx番目(0-origin)までの和を求める。(idx番目を含む) */
int bit_sum(const int bit[], int idx) {
int ret = 0;
if (idx < 0) return 0;
idx++;
while (idx > 0) {
ret += bit[idx - 1];
idx -= idx & (-idx);
}
return ret;
}
/* 0以上max未満の整数をランダムに返す関数 */
int rand_upto(int max) {
/* 必要ならもっといい実装をしてください */
return rand() % max;
}
int main(void) {
#ifndef PUTTERN2
/* 1の数は5個、0が15個 */
const int candidates_kind_num = 2; /* 乱数の候補の種類数 */
const int candidates[2] = {1, 0}; /* 乱数の候補 */
const int candidates_num[2] = {5, 15}; /* 各乱数の候補の個数 */
int candidates_bit[2]; /* どの乱数の候補が残っているかを管理するBIT (Binary Indexed Tree) */
#else
/* 0が10個、1が7個、2が3個 */
const int candidates_kind_num = 3;
const int candidates[3] = {0, 1, 2};
const int candidates_num[3] = {10, 7, 3};
int candidates_bit[3];
#endif
int i;
srand((unsigned int)time(NULL));
/* BITを初期化する */
for (i = 0; i < candidates_kind_num; i++) candidates_bit[i] = 0;
/* BITに各乱数の候補の残り数を加える */
for (i = 0; i < candidates_kind_num; i++) {
bit_add(candidates_bit, candidates_kind_num, i, candidates_num[i]);
}
for (;;) {
/* 乱数の候補の残り数 */
int left_candidates = bit_sum(candidates_bit, candidates_kind_num - 1);
/* 出す乱数の候補 */
int idx;
/* 二分探索で使用する変数 */
int left, right, mid, random_result_idx;
/* 実際に出た乱数 */
int random_result;
if (left_candidates <= 0) {
/* 出せる乱数が残っていない */
break;
}
/* どの候補を出すかを決定する */
idx = rand_upto(left_candidates);
/* 具体的にそれがどの候補に当たるのかを求める */
left = 0;
random_result_idx = right = candidates_kind_num - 1;
while (left <= right) {
mid = left + (right - left) / 2;
/* そこまでの和がidxを超える最小の添え字を求める */
if (idx < bit_sum(candidates_bit, mid)) {
if (random_result_idx > mid) random_result_idx = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
/* 出た候補の残り数を1減らす */
bit_add(candidates_bit, candidates_kind_num, random_result_idx, -1);
/* どの候補かという情報から具体的な候補を求める */
random_result = candidates[random_result_idx];
/* 出た乱数を出力する */
printf("%d ", random_result);
}
putchar('\n');
return 0;
}