配列nを用意して、2*nの配列に1~Z、又は1~9までの数字を格納します。3の場合、123,132,213,231,312,321の順列で、ルールは1の時は1つ間を空けて1を、2の時は2つ間を空けて2を・・・
つまり、3の場合は 231213,312132 の二つがルールと合致しているので答えとなります。
1~Zまでで、上記のようにルールに当てはまる場合のみを出力するプログラムを書きたいのですがうまくいきません。下に考えてみたものを載せます。どなたか分かる方ご教授願います。
#include<stdio.h>
int p[99]={0},a[99]={0};
int n;
int count;
main(){
int i;
void perm(int k);
while(1){
scanf("%d",&n); if(n<=0){break;}
for(i=1;i<=n;i++){p[i]=i;}
count=0;
perm(1);
}
}
void perm(int k){
int i,w;
if(k>n){
count++;
for(i=1;i<=n;i++){a[i]=p[i];}
for(i=1;i<=n;i++){a[i+a[i]+1]=a[i];}
printf("[%d]:",count);
for(i=1;i<=2*n;i++){printf("%3d",a[i]);} printf("\n");
}
else{
for(i=k;i<=n;i++){
w=p[k];p[k]=p[i];p[i]=w;
perm(k+1);
w=p[k];p[k]=p[i];p[i]=w;
}
}
}
No.4
- 回答日時:
確かに、要素数が3ないし5程度であれば、前半部分と後半部分でそれぞれ順列の
並び替えを行って、すべての場合について総当たりで調べることは可能でしょう。
しかし、たかだか9個だけでも、組み合わせ数は非現実的なものとなります。
1~9を用いるとすると、前半部分が9!(9の階乗)通り、同じく後半部分も9!通りで、
全組み合わせ数は (9!)×(9!)=約1300億通り。
総当たり法ではどのくらいの時間がかかるのか見当も付きません…。
というわけで、順列の並び替えではなく、別の手段で組み合わせ数を減らしていく
ことをお勧めします。
例えば、前半部分だけを見た場合、ルールにマッチするのは1文字目が8または9の
場合だけで、1~7になることは有り得ませんよね。
同様に2文字目は7~9のどれかになりますね(しかも1文字目と同じ数字は含まない)。
そう考えていくと、前半部分でルールにマッチする並びというのはかなり限られた
数に絞り込めると思います。
後半部分についても同様に絞り込めますね。
というより前半部分を逆並びにするだけですが。
あとはそれら前半と後半を組み合わせて、ルールにマッチしているかどうか調べます。
No.3
- 回答日時:
まだ理解し切れなく申し訳ない。
でもこれはちょっと難しいわ。
色々考えてみたけど一筋縄ではいかんぽい。
(1)順列を格納する
(2)解の全ての組み合わせ(しかも可変長)を出力する
(2)より(1)の方が難しくて、ちょっとお手上げ…。
そこで、このアルゴリズムを切り分けて考えるようにして
(1)についてもう一度、新規で質問を投稿することをお勧めします。
中途半端な回答になってしまい申し訳ありません。
お手数おかけしてすいません。
順列の格納と出力は以前のソースで出来ていると思ってたのですが。
n=3 の場合
a[0] a[1] a[2] の配列を用意
2*n なので
a[0] a[1] a[2] a[3] a[4] a[5]
1 2 3 0 0 0
1 3 2 0 0 0
2 1 3 0 0 0
2 3 1 0 0 0
3 2 1 0 0 0
3 1 2 0 0 0
#include<stdio.h>
int p[99]={0},a[99]={0};
int n;
int count;
main(){
int i;
void perm(int k);
while(1){
scanf("%d",&n); if(n<=0){break;}
for(i=1;i<=n;i++){p[i]=i;}
count=0;
perm(1);
}
}
void perm(int k){
int i,w;
if(k>n){
count++;
printf("[%d]:",count);
for(i=1;i<=2*n;i++){printf("%3d",p[i]);} printf("\n");
}
else{
for(i=k;i<=n;i++){
w=p[k];p[k]=p[i];p[i]=w;
perm(k+1);
w=p[k];p[k]=p[i];p[i]=w;
}
}
}
上記のソースから、(2)の組合せである
2 3 1 0 0 0
3 1 2 0 0 0
を
2 3 1 2 1 3
3 1 2 1 3 2
と出来ればと思っていたのですが。
色々と考えて頂きありがとうございました。
No.2
- 回答日時:
ルールに当てはまる場合のみを出力する
ということはだいたいわかるのですが
(前回はこの部分に特化した話です)
それ以前に
2*nの配列に1~Z、又は1~9までの数字を格納します。
こちらがわの格納ルールはどういうルールで順列が格納されているのか
がちょっとわかりずらいです。3の場合しかないので
scanf("%d",&n);
for(i=1;i<=n;i++){p[i]=i;}
あなたが考えたプログラムをみると
入力された数字の分までの配列に順数を入れています。
たとえばn=3 p[] ={0,1,2,3}
というような結果になるソースを記載されているようですが
説明ではn=3 p[] ={123,132,213,231,312,321}
という状態になるべきだと理解してしまいます。
上と下とでは解法が変わってきます。
そこで、どういうルールで順列が格納されるべきなのかを
ハッキリさせて欲しいと思っています。
できれば5の場合の例を書いてもらうとわかると思います。
この回答への補足
再びありがとうございます。
(どういうルールで順列が格納されるべきなのか)
これは、n=3 p[] ={123,132,213,231,312,321} という状態です。
5の場合というのは5の順列でしょうか?長くなりますが以下に
1 2 3 4 5
1 2 3 5 4
1 2 4 3 5
1 2 4 5 3
1 2 5 4 3
1 2 5 3 4
1 3 2 4 5
1 3 2 5 4
1 3 4 2 5
1 3 4 5 2
1 3 5 4 2
1 3 5 2 4
1 4 3 2 5
1 4 3 5 2
1 4 2 3 5
1 4 2 5 3
1 4 5 2 3
1 4 5 3 2
1 5 3 4 2
1 5 3 2 4
1 5 4 3 2
1 5 4 2 3
1 5 2 4 3
1 5 2 3 4
2 1 3 4 5
2 1 3 5 4
2 1 4 3 5
2 1 4 5 3
2 1 5 4 3
2 1 5 3 4
2 3 1 4 5
2 3 1 5 4
2 3 4 1 5
2 3 4 5 1
2 3 5 4 1
2 3 5 1 4
2 4 3 1 5
2 4 3 5 1
2 4 1 3 5
2 4 1 5 3
2 4 5 1 3
2 4 5 3 1
2 5 3 4 1
2 5 3 1 4
2 5 4 3 1
2 5 4 1 3
2 5 1 4 3
2 5 1 3 4
3 2 1 4 5
3 2 1 5 4
3 2 4 1 5
3 2 4 5 1
3 2 5 4 1
3 2 5 1 4
3 1 2 4 5
3 1 2 5 4
3 1 4 2 5
3 1 4 5 2
3 1 5 4 2
3 1 5 2 4
3 4 1 2 5
3 4 1 5 2
3 4 2 1 5
3 4 2 5 1
3 4 5 2 1
3 4 5 1 2
3 5 1 4 2
3 5 1 2 4
3 5 4 1 2
3 5 4 2 1
3 5 2 4 1
3 5 2 1 4
4 2 3 1 5
4 2 3 5 1
4 2 1 3 5
4 2 1 5 3
4 2 5 1 3
4 2 5 3 1
4 3 2 1 5
4 3 2 5 1
4 3 1 2 5
4 3 1 5 2
4 3 5 1 2
4 3 5 2 1
4 1 3 2 5
4 1 3 5 2
4 1 2 3 5
4 1 2 5 3
4 1 5 2 3
4 1 5 3 2
4 5 3 1 2
4 5 3 2 1
4 5 1 3 2
4 5 1 2 3
4 5 2 1 3
4 5 2 3 1
5 2 3 4 1
5 2 3 1 4
5 2 4 3 1
5 2 4 1 3
5 2 1 4 3
5 2 1 3 4
5 3 2 4 1
5 3 2 1 4
5 3 4 2 1
5 3 4 1 2
5 3 1 4 2
5 3 1 2 4
5 4 3 2 1
5 4 3 1 2
5 4 2 3 1
5 4 2 1 3
5 4 1 2 3
5 4 1 3 2
5 1 3 4 2
5 1 3 2 4
5 1 4 3 2
5 1 4 2 3
5 1 2 4 3
5 1 2 3 4
失礼しました。
n=3 のとき、
p[0]=1
p[1]=2
p[2]=3
p[0]=1
p[1]=3
p[2]=2
というように配列の要素にそれぞれ入れていく形でした。すいませんでした。
No.1
- 回答日時:
ややこしいアレですな。
意味を理解するのに時間かかりました。
調べたい数字を引数にして
戻り値は前にいくつ数字があるか返す front(int a)
戻り値は後ろにいくつ数字があるか返す after(int a)
というメソッドをそれぞれ実装すればいけるのでは?
変数内が
123456789
だとして,問題が7だとしたら
front(7) //6が返る
after(7) //2が返る
ように
各要素について検査し
front()+after()がルールに当てはまる場合
のみヒットとするようにしたらいけるのでは?
この回答への補足
回答ありがとうございます。なかなか意味を伝えることが出来ずすいませんでした。
このルールは、Langford's Problem(ラングフォードの問題)なのかなと思いましたが分かりません。
私のプログラミングは初心者に近い部類ですのでより簡単な方法で解決したいと思っています。
SAKENOSAKAさんのに指摘された方法はルールを確かめるということで良いでしょうか?それと、私のプログラムに実装するという形でしょうか?
何分初心者ですので、より具体的な解法のご教授をお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(プログラミング・Web制作) 十進BASICでの再帰についての質問です。 2 2022/11/18 09:17
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# C言語 3 2022/11/09 13:27
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# 10人分の生徒の英語の点数{32,34,41,38,40,26,14,46,42,50} と数学の点 2 2022/05/26 21:31
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
へんな現象
-
#define _CRT_SECURE_NO_WARNIN...
-
【C++】関数ポインタの使い方
-
複数桁10進数の*桁目だけを抽出...
-
if と配列の組み合わせ
-
(int *)の意味
-
アスタリスクで正方形
-
プログラミングペーパーテスト ...
-
C言語でDxlibを使って3x3の奇数...
-
C言語 巡回セールスマン問題 2-...
-
C言語 エラーの原因がわからな...
-
実数の整数部,小数部の取得
-
数字列を3桁ごとにカンマで区切...
-
課題なんですが・・・
-
C 言語の Gauss Jordan 法について
-
ラップ関数とはどんなものですか?
-
C言語 配列と関数の練習問題
-
教えてください(丸罰ゲーム)
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
「指定されたキャストは有効で...
-
C言語 配列と関数の練習問題
-
複数桁10進数の*桁目だけを抽出...
-
(int *)の意味
-
if と配列の組み合わせ
-
ラップ関数とはどんなものですか?
-
卒業研究でよく分からないとこ...
-
【C++】関数ポインタの使い方
-
c言語
-
足して100になるような乱数のア...
-
C言語初心者です、、、お助けく...
-
数字列を3桁ごとにカンマで区切...
-
C言語 エラーの原因がわからな...
-
実数の整数部,小数部の取得
-
課題でつまってます・・・
-
商と剰余を同時に求める(C言語)
-
C言語の配列をC++のvectorに高...
-
std::set<int> で、ある値が何...
おすすめ情報