タイトルにもあるとおり、
1から100までの数字をそれぞれ1つずつを100個使って、偶数もしくは奇数が4回以上続かないように並べる(配列を作る)アルゴリズムを教えていただきたいです。
例えば
x = [99,1,4,5,2,66,45...]
length(x)
→100
のようなものを作成したいです。
条件にもあるとおり、よくないパターンは
1, 偶数が4回以上続いている(奇数も同様)
x = [77,2,4,3,66,88,42,72]
2, 同じ数値がある(下の例では99)
x = [99,1,4,5,2,66,99...]
同じ数値を使わずに1から100までの数値を使ってランダムな配列を作成することは、組み込み関数(MATLAB)を使ってできますが、良くないパターン1の条件を満たせません。
自分がわかる言語はpythonとmatlabですので、そちらの言語で教えていただくのがベストですが、難しい場合は、言葉で説明していただけると幸いです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/01/17 03:03
2022/01/17 22:38

回答12件
0
普通にランダムに取り出しながら配列を埋めていき、連続が 4 になった場合は選び直しをするというので良いと思います。
選び直しは、出せる数が偶数か奇数か決まっているので、その中から選びます。
出た偶数の数が極端に多くなった場合、残りは奇数が多いので奇数が出る確率が高くなり、逆もまた然りなので、自動的にバランスが取れるでしょう。
偶数奇数のどちらかの残りがもう片方の 1/4 未満になった場合は破綻しますが、最終局面以外ではそこまで極端な偏りは生まれないと思います。1/4 になった時点で偶奇の配置が決まるので、そこからは偶数を出すか奇数を出すか決めてから取り出すアルゴリズムに変わります。
例えば、偶数 2 個、奇数 8 個が残った場合、それまでで最後に出た数が偶数であれば、奇奇奇偶奇奇奇偶の配置になり、最後に出た数が奇数であれば、偶奇奇奇偶奇奇奇になります。
正確に言えば、最後の奇奇奇偶については、最初が奇数であれば後の並びはランダムで問題ありません。
追記
1/4 は 1/3 の誤りです。
投稿2022/01/17 02:23
編集2022/01/17 02:55総合スコア28673
0
いちばん手抜きな方法としては、「何も考えずにシャッフルして、条件を満たさなければもう一度」を繰り返す方法が考えられます。
投稿2022/01/17 00:51
総合スコア146544
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
題意をみたす列を全パターン出せそうな方法(途中,考察をダラダラと記述)
Step1: 1以上100以下の奇数を Fisher-Yates shuffle しておきます.
MATLABなら fy = randperm(100); のあと fyodd=fy(mod(fy,2)==1); など.
また,python なら import random から
fyodd=list(range(1,101,2)) をして random.shuffle(fyodd) など.
random.shuffle() はfyoddの中身を直接書きかえてしまうのですね.
Step2: 同様に,1以上100以下の偶数を Fisher-Yates shuffle しておきます.
次に,偶奇の切り替わり回数は最多で99回,最少で33回です.
(切り替わりが最少となる例) 奇奇奇,偶偶偶, ... ,奇奇奇,偶偶偶,奇奇,偶偶(カンマが33個)
連続する{奇数/偶数}のかたまりを「1かたまり」と数えると,
かたまりの個数の最大値は100,最小値は34です.
また,減らせるかたまりの個数=減らせる偶奇の切り替わりの回数 です.
これをmとおくと,0<=m<=66 となります.
Step3: 0以上66以下の整数mをランダムに決定します.
題意を満たす列における{奇数/偶数}のかたまりの数の最大値は各50,最小値は各17です.
{奇数/偶数}のかたまりの個数をそれぞれ{mo回/me回}減らすことにして,
0<=mo<=33 かつ 0<=me<=33 かつ abs(mo-me)<=1 となるように mo, me を決定します.
Step4: mが偶数の場合,mo=me=m/2とします.また,mが奇数の場合,moとmeのうち片方を(m+1)/2,もう片方を(m-1)/2とします.
奇数のかたまりの個数を減らしていきます.
かたまりの個数を1つ減らすごとに,いずれか1つのかたまりのサイズが大きくなります(増えるサイズは後述).
Step5: 1以上49以下の数をmo個並べてできる列 {ro_1, ro_2, ... , ro_mo}を考えます.また,もしmoの値が0ならばStep8に移ります.
Step6: 次に「奇,奇, ... ,奇」という(かたまりサイズ1の奇数50個をカンマで区切った)並びを考えます.
Step7: i = 1, 2, ... ,mo に対して以下を行います:「もし,Step6の時点で左から ro_i番目の位置にあったカンマを取り除いても,奇数が4つ以上連続しないならば,そのカンマを取り除く(これにより,取り除くカンマの左にあったかたまりのサイズが「取り除くカンマの両脇にあった2つのかたまりのサイズの和」となる)」
同様に,偶数のかたまりの個数を減らしていきます.
Step8: 1以上49以下の数をme個並べてできる列 {re_1, re_2, ... , re_me}を考えます.また,もしmeの値が0ならばStep11に移ります.
Step9: 次に「偶,偶, ... ,偶」という(かたまりサイズ1の偶数50個をカンマで区切った)並びを考えます.
Step10: i = 1, 2, ... ,me に対して以下を行います:「もし,Step6の時点で左から re_i番目の位置にあったカンマを取り除いても,偶数が4つ以上連続しないならば,そのカンマを取り除く(これにより,取り除くカンマの左にあったかたまりのサイズが「取り除くカンマの両脇にあった2つのかたまりのサイズの和」となる)」
以上の操作によって生成された最大サイズ3の偶奇のかたまりを並べていきます.
Step11: もし mo-me=1 ならば,奇数のかたまりから開始して,以下{奇数/偶数}のかたまりを交互に置いていく.また,もし me-mo=1 ならば,偶数のかたまりから開始して{奇数/偶数}のかたまりを交互に置いていく.いずれにも該当しなければ,me=moなので,{奇数/偶数}どちらのかたまりから開始しても良いが,以下{奇数/偶数}のかたまりを交互に置いていく.
その結果,mo-me=1 の場合が奇数のかたまりで終わり,me-mo=1 の場合は偶数のかたまりで終わります.
また,me=mo で奇数のかたまりから開始した場合は偶数で,偶数のかたまりから開始した場合は奇数で,それぞれ終わります.
題意をみたす列は,必ずこの手法で表現し得るのではないかと思っています.
ただし,出方が一様かどうかの検証はしていません.
投稿2022/01/28 04:11
編集2022/01/28 08:43総合スコア106
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
奇数50個、偶数50個に分ける
それぞれを任意の順番に並び替える
偶奇偶奇…偶奇(またはその逆)の順に並べる
「3つ以下ずつ」、の組み合わせにする(下記参照)
(偶奇偶)(奇偶)(奇)(偶奇偶)(奇偶奇)…(偶)(奇偶奇)
()内を任意の順番に並び替える
完全な等確率ではないですが、結構簡単に実装できますよ。
投稿2022/01/18 00:23
編集2022/01/18 09:31総合スコア1722
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/01/18 00:42
2022/01/28 05:57 編集
2022/01/30 01:48 編集

0
18~49の整数をランダムに選ぶ。この数字をnとする
(16~50の整数でもいいですが、説明が複雑になるので端折ります)
-1~1の整数をランダムに選ぶ。この数字をkとし、m=n+kとする
1~100を偶数、奇数に分けてそれぞれの山をシャッフルする
要素数1のグループをn個、奇数の山から作る
できたグループに1~nの番号をつける
そして1~nの整数をランダムに生成し、出た数の番号のグループに奇数の山から1つ配る
(ただし、要素数が3のグループには配らない)
これを奇数の山がなくなるまで繰り返す
次に、要素数1のグループをm個、偶数の山から作る
できたグループに1~mの番号をつける
そして1~mの整数をランダムに生成し、出た数の番号のグループに偶数の山から1つ配る
(ただし、要素数が3のグループには配らない)
これを偶数の山がなくなるまで繰り返す
あとは、
k=-1の時は奇数のグループから始めて交互にグループを並べる
k=1の時は偶数のグループから始めて交互にグループを並べる
k=0の時はどちらが先でもいいので交互にグループを並べる
投稿2022/01/17 22:05
編集2022/01/17 23:06総合スコア282
0
偶数,奇数を別の配列に分けて,それぞれをランダムシャッフルしておく
↓
偶数,奇数のどちらかの配列から要素を持ってきては,現在の結果数列の挿入可能な位置のいずれかに挿入する
(もしも挿入可能な位置が無い場合は別の側の配列から要素を持ってきて処理することとする)
というだけで良いのでは.
(結果数列を線形リストとして考えて,ルール的に挿入可能な位置の中から挿入位置をランダムで選ぶだけの話)
投稿2022/01/17 03:59
編集2022/01/17 04:05総合スコア12151
0
偶数50個奇数50個の並びで4個以上連続しない並びを決めれば、あとはそれに偶数の順列と奇数の順列を等しい確率で割り当てればいいだけなので、問題は偶数50個と奇数50個の4個以上連続しない並びを求めるところだけです。
この下長々と書いてますがおそらく相当わかりづらいのでさわりだけ言えば、パターン数を求めてパターン数の比率に応じて選ぶことを繰り返せば全パターンを等確率で選んだり、全パターンを列挙することができます。
d(len, evenCount, prev2, prev1, prev0) を長さ(len >= 3)でそのうち偶数をevenCount個使った並びで、末尾から2文字目、1文字目、0文字目の偶奇性がprev2, prev1, prev0で表せるようなもののパターン数とすると
len == 3 のとき、prev2, prev1, prev0のうち、偶数であるようなものの個数がevenCount個であるものは 1 、そうでなければ 0 len > 3 のとき、 evenCount not in [0, len] ならば 0 そうでないとき if prev0 is even then//最後が偶数 if prev1 is even && prev2 is even then//末尾3文字がすべて偶数 => 4文字前は奇数でなければならない d(len - 1, evenCount - 1, odd, prev2, prev1) else//そうでないなら偶数でも奇数でもいい d(len - 1, evenCount - 1, even, prev2, prev1) + d(len - 1, evenCount - 1, odd, prev2, prev1) else//最後が奇数の場合略 if prev1 is odd && prev2 is odd then d(len - 1, evenCount, even, prev2, prev1) else d(len - 1, evenCount, even, prev2, prev1) + d(len - 1, evenCount, odd, prev2, prev1)
となります。
これが分かればあとは、構築する関数s(len, evenCount, prev2, prev1, prev0)を同様に
len == 3 のとき、prev2 + prev1 + prev0 len > 3 のとき、 if prev0 is even then if prev1 is even && prev2 is even then s(len - 1, evenCount - 1, odd, prev2, prev1) + even else which = random from [0, d(len, evenCount, prev2, prev1, prev0)) if which < d(len - 1, evenCount - 1, even, prev2, prev1) then s(len - 1, evenCount - 1, even, prev2, prev1) + even else s(len - 1, evenCount - 1, odd, prev2, prev1) + even else//以下略
とでき、最終的にほしい列としては
allPattern = sum of d(100, 50, prev2, prev1, prev0) forall (prev2, prev1, prev0) which = random from [0, allPattern) pattern = 0 for prev2 in (even, odd) for prev1 in (even, odd) for prev0 in (even, odd) pattern += d(100, 50, prev2, prev1, prev0) if witch < pattern then return s(100, 50, prev2, prev1, prev0)
という感じで求められます。
投稿2022/01/17 03:04
総合スコア2052
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
3連続奇数or偶数が続いた場合は別のグループから選択するプログラムを実装しました。
配列数、奇数、偶数それぞれの最大連続数を設定できる形です。
条件に沿う形で出来る限りランダム性を担保していると思います。
尚、条件に合う数列が生成できないケースでは、一から再計算します。
また、その失敗する確率も計算させましたが、
n=100, max_odd_sequense=3, max_even_sequense=3の条件では、11%程度でした。
python
1import random 2import numpy as np 3 4def make_conditional_sequence(n=100, max_odd_sequense=3, max_even_sequense=3, failed=0): 5 choice_list = list(range(n)) 6 random_array = [] 7 #print('Start') 8 for i in range(n): 9 before_odd_array = random_array[-max_odd_sequense:] 10 before_even_array = random_array[-max_even_sequense:] 11 is_odd = [True if i%2 !=0 else False for i in before_odd_array] 12 is_even =[True if i%2 ==0 else False for i in before_even_array] 13 14 if sum(is_odd) >= max_odd_sequense: 15 even_list = [i for i in choice_list if i%2 == 0] 16 if len(even_list) == 0: 17 #print('this trial failed') 18 return make_conditional_sequence(n, max_odd_sequense, max_even_sequense, failed=failed+1) 19 else: 20 choiced = random.choice(even_list) 21 #print('random choiced from even', choiced) 22 23 24 elif sum(is_even) >= max_even_sequense: 25 odd_list = [i for i in choice_list if i%2 != 0] 26 if len(odd_list) == 0: 27 return make_conditional_sequence(n, max_odd_sequense, max_even_sequense, failed=failed+1) 28 else: 29 choiced = random.choice(odd_list) 30 31 else: 32 choiced = random.choice(choice_list) 33 34 choice_list.remove(choiced) 35 random_array.append(choiced) 36 37 #print(f'failed {failed}') 38 39 return random_array, failed 40 41failed_list = [] 42for i in range(100): 43 random_ , failed = make_conditional_sequence(n=100, max_odd_sequense=3, max_even_sequense=3) 44 #print(random_) 45 failed_list.append(failed) 46 47 48print(failed_list) 49p = sum(failed_list) / sum([i+1 for i in failed_list]) 50print(p)
投稿2022/01/17 02:59
編集2022/01/17 10:11総合スコア152
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
連続で出てくる数字の回数が均等になってしまいますが
偶数と奇数のグループに分けて
3回連続で出てくる偶数(奇数)を8グループ
2回連続で出てくる偶数(奇数)を8グループ
1回連続で出てくる偶数(奇数)を10グループ
作成してそれを偶数奇数交互に配置していけば要件を満たすのではないでしょうか?
この場合、偏った偶奇が50回繰り返すパターンなどは生成されませんが
投稿2022/01/17 02:59
総合スコア1426
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
100個の数値を,数値4個からなるグループに分けることを考える.(25個のグループになる)
以下を12回繰り返すことでグループを24個作り出す.
- 新しいグループに含める偶数の個数Nを{1,2,3}から乱数で決める.
まだいずれのグループにも振り分けられていない数値群からてきとーに{偶数をN個,奇数を4-N個}もってきてグループを作る.
- このとき,もうひとつのグループを{偶数を4-N個,奇数をN個}という分配で同様に作る.
残った数値4個を最後の(25個目の)グループにする.
これで25個のグループができた.
↓
これらのグループを連結していくことで結果の数列(100個の数値の並び)を作ることを考える.
- 数列は最初は空である.
- 「いずれかのグループを選択しては数列の末尾に追加する」を25回繰り返すことで数列を完成させる.
- あるグループを数列末尾に追加する際,このグループ内の4個の数値の並びは,数列に追加してもOKなパターン(追加結果が偶数or奇数4連以上の並びを作らないパターン)からランダムで決める.
といった感じで.
投稿2022/01/17 02:30
総合スコア12151
0
均等な確率になるかは分かりませんが、 以下のような処理で条件を満たす配列は得られそうです。
ただし以下の処理では、条件は満たすが出現しないパターンがあるようです。
Python
1# 1から100までの数字を奇数と偶数それぞれ別の配列に入れて要素をシャッフルする。 2 3# 以下、2つの配列のどちらも空になるまでループ 4 5 # 奇数、偶数どちらの配列から値を採るかを以下のルールで決定する。 6 # 7 # - 2つの配列の個数の差が3個以上なら多いほうを採る。 8 # 「連続した値」が3回以上なら、反対のほうを採る。 9 # - いずれかの配列が空なら、まだ残っているほうを採る。 10 # - それ以外なら奇数または偶数いずれかをランダムに採る。 11 12 # 採るほうの配列先頭から値を抜き取り結果配列に追加する。 13 # 採るほうが変わったら「連続した値」を1回にクリアする。
投稿2022/01/17 01:15
編集2022/01/17 01:59総合スコア38352
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/01/17 01:21

0
続かなければいいだけなら奇数、偶数、奇数、偶数、・・・・
の順で処理すればいいでしょう。
偶数と奇数をそれぞれ配列に抽出してシャッフルして順番に抜き出す感じです。
4つ以上続かないという条件をつけた時点ですでにランダム性は損なわれています
sample
ロジックの質問なのでjsでサンプル提示します
javascript
1<div id="view" style="word-break:break-all;"></div> 2<script> 3const num=50; 4const cnt=3; 5const chusen=(num,cnt,len=null)=>{ 6 let tmp_i; 7 let tmp_num; 8 let counta=0; 9 const ret={}; 10 const retry=1000; 11 do{ 12 tmp_num=num; 13 ret.len=0; 14 ret.retry=0; 15 for(let i=cnt;i>=1;i--){ 16 tmp_i=(i>1)?parseInt(Math.random()*parseInt(tmp_num/i)):tmp_num; 17 ret[i]=tmp_i; 18 ret.len+=tmp_i; 19 tmp_num-=tmp_i*i; 20 } 21 if(counta++>=retry) return null; 22 ret['retry']=counta; 23 24 }while(len!=null && ![0,1].includes(len - ret.len)); 25 return ret; 26}; 27const res=[]; 28const list={ 29 odd:Array(num).fill(null).map((_,x)=>[x*2+1,Math.random()]).sort((x,y)=>x[1]-y[1]).map(x=>x[0]), 30 even:Array(num).fill(null).map((_,x)=>[x*2+2,Math.random()]).sort((x,y)=>x[1]-y[1]).map(x=>x[0]), 31}; 32const c1=chusen(num,cnt); 33console.log(c1); 34const c2=Array(cnt).fill(null).map((_,x)=>Array(c1[x+1]).fill(x+1)).flat().map(x=>[x,Math.random()]).sort((x,y)=>x[1]-y[1]).map(x=>x[0]); 35console.log(c2); 36const c3=chusen(num,cnt,c1.len); 37console.log(c3); 38const c4=Array(cnt).fill(null).map((_,x)=>Array(c3[x+1]).fill(x+1)).flat().map(x=>[x,Math.random()]).sort((x,y)=>x[1]-y[1]).map(x=>x[0]); 39console.log(c4); 40 41let choice=Math.random()<0.5?"odd":"even"; 42for(var i=0;i<c2.length;i++){ 43 [c2,c4].forEach(x=>{ 44 if(tmp=list[choice].splice(0,x[i])) res.push(tmp); 45 choice=choice=="odd"?"even":"odd"; 46 }); 47} 48view.textContent=res.flat().join(','); 49</script>
調整しました
投稿2022/01/17 00:44
編集2022/01/17 05:53総合スコア117674
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。