ページ 11

rand関数で被らない値を出す方法

Posted: 2010年3月15日(月) 18:38
by RIO
0~9で被らない数字を3つ出す方法はないでしょうか?

現在、下記の様に実装しているのですが無駄なのでしょうか?
int a = rand%10;
int b = rand%10;
int c = rand%10;

while(1){
    if(a!=b)break;
    else b = rand%10;
}

while(1){
    if(a!=c && b!=c) break;
    else c = rand%10;
}

Re:rand関数で被らない値を出す方法

Posted: 2010年3月15日(月) 19:06
by 初級者
rand % 10
で、コンパイルできていますか?

Re:rand関数で被らない値を出す方法

Posted: 2010年3月15日(月) 19:11
by RIO
すみません。直接書いていたので・・・。
rand()と書いてありコンパイルは通っております。

ロジックがわからないので質問させて頂きました。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月15日(月) 19:17
by バグ
0~9が格納された配列をシャッフルして、先頭の3つを取り出せばいいですよ。
理屈はトランプを切るのと同じです。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月15日(月) 20:03
by Dixq (管理人)
バグさんの補足でシャッフルは例えばこんなプログラムでどうでしょう^^
#include<stdio.h> 
#include<stdlib.h>
#include<time.h>

void swap( int *a, int *b ){
    int t = *a;
    *a = *b;
    *b = t;
}

int main(){
    int i=0,r,arr[10]={0,1,2,3,4,5,6,7,8,9};
    srand((unsigned)time(NULL));
    while( i < 10 ){
        r = rand() % 10;
        if( r == i ){    //同じもの交換してもショウガナイ
            continue;    //のでもう一度
        }
        swap( &arr, &arr[[/url] );
        i++;
    }
    for( i=0; i<10; i++ ){
        printf("%d ", arr);
    }
    return 0;
}  

実行結果
2 9 7 4 8 6 3 5 0 1

 
最初の3つを表示させたければ最後のfor文の上限を3にすればいいですね。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月15日(月) 20:10
by Dixq (管理人)
解り難くてよければ
int main(){
    int i,arr[10]={0,1,2,3,4,5,6,7,8,9};
    srand((unsigned)time(NULL));
    for( i=0; i<10; i++)
        swap( &arr, &arr[(((rand() % 9) + (i + 1)) % 10)] );
    return 0;
}
 
 
これで同じこと出来ますね。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月16日(火) 00:19
by RIO
皆様ご回答ありがとうございます。 管理人様まで・・・。
こんなに回答が頂けるとは思いませんでした。

なるほど・・・先頭を取るのですか・・・。
そのように考えたことがありませんでした。
ありがとうございました。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月16日(火) 01:43
by たかぎ
(Cではなく)C++を使っていて、rand関数にこだわらないのであれば、std::random_shuffle関数テンプレートを使えばもっと簡単になります。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月16日(火) 05:24
by 初級者
同じ値どうしの交換を排除しなくてもよいのでは
ないかと思います。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月16日(火) 08:54
by バグ
「Fisher-Yates」でググると詳しいことがヒットするかと思います。

Re:rand関数で被らない値を出す方法

Posted: 2010年3月16日(火) 09:04
by たいちう
ぱっと見ただけですが、管理人さんの最初のロジックでは、
以下のような数列を生成できないと思います。
偶数回のswapでは不可能でしょう。
(n == 2 の場合を考えるのが簡単でしょう。)

{1,0,2,3,4,5,6,7,8,9};

後で時間が取れたら補足します。
(それまでに誰かの補足がなければ)

Re:rand関数で被らない値を出す方法

Posted: 2010年3月16日(火) 09:20
by たいちう
説明しているページを発見。
http://ray.sakura.ne.jp/tips/shaffle.html

Re:rand関数で被らない値を出す方法

Posted: 2010年3月16日(火) 20:50
by バグ
もう解決したようですがサンプルです。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define N 10

int main(void)
{
    int i = 0, j = 0, temp = 0, array[N];

    // 乱数の種を設定する
    srand((unsigned)time(NULL));

    // 配列の初期化
    for (i = 0; i < N; ++i)
    {
        array = i;
    }

    // Fisher-Yatesによるシャッフル処理
    for (i = N - 1; i > 1; --i)
    {
        j = rand() % (i + 1);
        temp = array[j];
        array[j] = array;
        array = temp;
    }

    // シャッフルした配列の表示
    for (i = 0; i < N; ++i)
    {
        printf("%d\n", array);
    }

    return 0;
}