ページ 1 / 1
10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月14日(月) 20:01
by テントウムシ
10個の配列から被らないようにランダムに5つの値を取りだしたいです。
下記の様なソースを考えてみたのですが""の部分の書き方がわかりません・・・。
※わからないというより ==&&と複数書かなければいけないのでしょうか?
もっと効率のよいPGはないでしょうか?
int Num[10] = { 1,2,3,4,5, 6,7,8,9,10 };
int Array[5];
while(1){
for(int i=0; i<5; i++){
Array = rand()%10;
}
if("全部違ってたら")break;
}
Re:10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月14日(月) 20:23
by たかぎ
std::random_shuffleでかき混ぜたあと、最初から5つを取り出せばOKです。
Re:10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月14日(月) 20:32
by MNS
一応、for文を重ねることによって
while(1){
for(int i=0; i<5; i++)
{
Array = rand()%10;
}
for(int x=0; x<5; ++x)
{
for(int y=0; y<5; ++y)
{
if(x!=y && Array[x]==Array[y])
{
goto CONTINUE;
}
}
}
break;
CONTINUE:
continue;
}
と書くことも出来ますが、効率は良くないでしょう。スマートでもありませんね。
それよりは、たかぎさんが仰るような、
そもそも値が重複しないように取り出す手法をとったほうが無難です。
Re:10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月14日(月) 20:37
by シエル
簡単に作ってみました。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void main(void)
{
int Num[10] = { 1,2,3,4,5, 6,7,8,9,10 };
int random[5];
int tmp;
int j;
srand((unsigned)time(NULL));
for(int i=0;i<5;i++){
random
=0;
while(1){
tmp=rand()%10;
for(j=0;j<i+1;j++){
if(random[j]==tmp){
break;
}
}
if(j==i+1){
random=tmp;
break;
}
}
}
for(int s=0;s<5;s++){
printf("ランダム数字=%d\n",random);
}
for(int x=0;x<5;x++){
printf("配列の数字読み込み=%d\n",Num[random[x]]);
}
} 
Re:10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月14日(月) 21:30
by ideyan
while(1)に対抗して(笑)
int Num[10] = { 1,2,3,4,5,6,7,8,9,10 };
int Array[5];
int i=0,j=0,tmp;
srand((unsigned)time(NULL));
while(i<5){
tmp = rand()%10;
for(j=0;j<i;++j){
if(Array[j]==Num[tmp])break;
}
if(j==i){
Array=Num[tmp];
++i;
}
}
でもやってることは皆さんと変わらないw
最初から被らないようにするのがいいですよねぇ。
Re:10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月14日(月) 22:11
by シエル
ideyanさんに横槍を入れるようで申し訳ないですが、
ideyanさんのコードだとNumの配列内に同じ数字があった場合は
その数字は一回しか選ばれない気がします。
間違ってたらすいません。
Re:10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月14日(月) 22:36
by ideyan
ん、あぁ。
元々の配列も重複無しかと思ってたんですが
よく見たら特にそんなことは書いてないですね^^;
というわけで修正版。
欠点は配列の要素の数と同じ個数のバッファを必要とすることです。
(同じ長さである必要は無いですがビット演算面倒です。。。)
int Num[10] = { 1,2,3,4,5,6,7,8,9,10 };
char flag[10];
int Array[5];
int i=0,tmp;
srand((unsigned)time(NULL));
for(i=0;i<10;++i)flag=0;
i=0;
while(i<5){
tmp = rand()%10;
if(!flag[tmp]){
flag[tmp]=1;
Array[i++]=Num[tmp];
}
}
Re:10個の配列から被らないように5つの値を取りだす
Posted: 2010年6月15日(火) 15:11
by めるぽん
たかぎさんの書いているのが一番スマートが気がしますね。
#include <algorithm>
#include <iostream>
int main()
{
int Num[10] = { 1,2,3,4,5,6,7,8,9,10 };
int Array[5];
std::random_shuffle(Num, Num + 10);
std::copy(Num, Num + 5, Array);
for (int i = 0; i < 5; i++) std::cout << Array << std::endl;
}
もし元の配列に重複する値があるなら、std::sort して std::unique で削除してしまえばいいかと。
#include <algorithm>
#include <iostream>
#include <iterator>
#include <cassert>
int main()
{
int Num[10] = { 8,2,3,2,4,5,1,5,8,9 };
int Array[5];
std::sort(Num, Num + 10);
int* last = std::unique(Num, Num + 10);
assert(std::distance(Num, last) >= 5); // 5個以上は unique な値が必要
std::random_shuffle(Num, last);
std::copy(Num, Num + 5, Array);
for (int i = 0; i < 5; i++) std::cout << Array << std::endl;
}