質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

2回答

999閲覧

バックトラック法での経路探索の結果を並び替えたいです。

rike

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2021/12/15 07:00

やりたいこと

C言語でのバックトラック法の経路探索について勉強しています。
下に示すソースコードの実行結果を
文字数の小さい順番に並び替えることはできますか?
ソースコードは以下のサイトを参考にしたものです。
http://www.nct9.ne.jp/m_hiroi/linux/clang16.html

#include <stdio.h> #include <stdbool.h> enum {S, A, B, C, D, E, F, G}; #define N 7 #define M 4 // 隣接リスト int adjacent[N + 1][M] = { {S}, {B, C, S}, {A, C, D, S}, {A, B, E, S}, {B, E, F, S}, {C, D, G, S}, {D, S}, {E, S}, }; // 経路 int path[N]; bool visited[N + 1]; // 経路の表示 void print_path(int n) { for (int i = 0; i < n; i++) printf("%c ", 'A' + path[i] - 1); printf("\n"); } // 深さ優先探索 void dfs(int n, int goal) { int x = path[n - 1]; if (x == goal) { print_path(n); } else { for (int i = 0; i < M; i++) { int y = adjacent[x][i]; if (y == 0) break; if (!visited[y]) { path[n] = y; visited[y] = true; dfs(n + 1, goal); visited[y] = false; } } } } int main(void) { path[0] = A; visited[A] = true; dfs(1, G); return 0; }

実行結果

A B C E G A B D E G A C B D E G A C E G

試したこと

文字列を他の文字列の配列に格納して、
その文字列で昇順にできるか試しました。
出来ませんでした。

他の探索方法を用いれば、文字列を並び替えることなく昇順の結果を実行出来ることは認識しております。
ただ、今回は出来ればバックトラック法を活用できたらよいなと考えています。
プログラミング言語初心者ですので、そもそもこのソースコードで文字の並び替えが可能なのかすらわかりません。
出来ないようでしたら、諦めて別の探索方法を用いるつもりです。
拙い文章ですが、ご協力いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/12/15 07:16

> 実行結果 は,「4つの経路が見つかった」という結果表示なのだと見えますが, 本件の話が「4つの経路が見つかった後で → それらを並び替える」なのであれば, 少なくとも,「並び替える」処理を行う時点で「4つの経路」なるデータが存在していなければならないでしょう. なので,まずは 「探索処理の結果データは,見つかった分だけ全部どこかに保持される」という形のプログラムにする必要があるでしょう. (→それは可能ですか?)
fana

2021/12/15 07:37 編集

さて,無事に「全経路データがどこかに保持される」形にできたならば, 問題は「こういうデータがあるんだけど,並び替えるにはどうすればいい?」になります. 話は純粋な「ある形のデータをソートする方法(あるいはその実装)」です. つまりこの時点で,もはやデータの出所や内容は問題と無関係な事柄となります. そのデータを得る手段がバックトラック法だったとか,そもそもデータが経路を表すものだとかいう情報は無用となります.
fana

2021/12/15 07:45

というわけで,とりあえず ・関数 dfs の中で経路を表示しているのをやめて,dfs は見つかった経路をどこかに(見つかった分だけ全て)保存する ・結果の表示は main 関数内( dfs の実行後.return の直前あたり)でまとめて行う という形をまずは目指すと良いのではないかと.
rike

2021/12/15 07:46

回答ありがとうございます。 データを格納するのは、何かしらのファイルにデータを保存するということでしょうか。 print_pathの結果をテキストファイルなどに書き込めば良いかと考えました。 fopen,fprint等を使ってやってみたのですが、コードを書く場所が悪いのか、うまく出来ません。 fprintを使う際、 print_pathを引数にするのかと思ったのですが、voidで設定してあるのでできません。 どこの箇所を引数にすれば良いのでしょうか。。
fana

2021/12/15 07:51

ファイルを介在させてもまぁ良いですが,とりあえず 変数 に格納する感じにすればどうでしょう. (理屈上の経路の最大数がいくつになるのかはわかりませんが) まずは簡便に「経路データを最大でX個まで保持できるとして」実装するならば, 単一の経路を表すデータの型を仮に Route 型だとすれば, #define X 100 //何個くらいあればいいのかわからんですが Route FoundRoute[X]; //X個までの経路データを持てる int nFoundRoute = 0; //見つかった経路の個数カウント用 みたいな変数でも用意すればここに貯め込んでいけるでしょう.
fana

2021/12/15 07:57 編集

Route の実際の型は適当に都合よく決めればよいでしょう. struct Route{ char Str[N+1]; }; //結局文字列かよ^^ みたいな物でも良いのかもしれません. 現状,経路が1個見つかる度に関数 print_path が呼ばれて,そこで見つかった経路を表示しているのであれば(そんな感じに見えますが,そこらへんの実情は確認してください), print_path を呼んでいる場所を適当に別の関数を呼ぶように書換え,その関数内で見つかった経路情報を上記の変数に格納する作業をすればよいのではないでしょうか.
guest

回答2

0

バックトラックによる検索と結果の(ソート)表示は全く関係ありませんので、お互いのデータの持ち方さえ合わせれば、組み合わせは自由です。

以下は文字列として (alloc した )buf に保存する形です。

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <stdbool.h> 5 6enum {S, A, B, C, D, E, F, G}; 7 8#define N 7 9#define M 4 10 11// 隣接リスト 12int adjacent[N + 1][M] = { 13 {S}, 14 {B, C, S}, 15 {A, C, D, S}, 16 {A, B, E, S}, 17 {B, E, F, S}, 18 {C, D, G, S}, 19 {D, S}, 20 {E, S}, 21}; 22 23// 経路 24int path[N]; 25bool visited[N + 1]; 26 27char *buf = NULL; 28char buf_size = 0; 29int buf_lastindex = 0; 30int buf_strcount = 0; 31 32//ソート 33void sort(char *a[], int n) { 34 for(int i=0; i<n-1; i++) { 35 for(int j=i+1; j<n; j++) { 36 int s = strlen(a[i]) - strlen(a[j]); 37 if(s == 0) s = strcmp(a[i], a[j]); 38 if(s > 0) { char *t=a[i]; a[i]=a[j]; a[j]=t; } 39 } 40 } 41} 42//ソートして表示(して開放) 43void sort_and_print() { 44 if(buf == NULL) return; 45 char *paths[buf_strcount]; 46 for(int i=0, j=0; i<buf_strcount; j+=strlen(paths[i++])+1) paths[i] = &buf[j]; 47 sort(paths, buf_strcount); 48 for(int i=0; i<buf_strcount; i++) printf("%s\n", paths[i]); 49 free(buf); 50} 51//文字列化して保存 52void store_path(int n) { 53 if(buf_lastindex+(n+1) >= buf_size) { 54 buf_size += (N+1); 55 buf = realloc(buf, buf_size); //buf=NULL なら malloc 同等 56 if(buf == NULL) exit(1); //拡張できなかったら(行儀悪く)即終了 57 } 58 for(int i=0; i<n; i++) buf[buf_lastindex++] = 'A'+(path[i]-1); 59 buf[buf_lastindex++] = 0; //End Of String 60 buf_strcount++; 61} 62 63// 経路の表示 64//void print_path(int n) { 65// for (int i = 0; i < n; i++) 66// printf("%c ", 'A' + path[i] - 1); 67// printf("\n"); 68//} 69 70// 深さ優先探索 71void dfs(int n, int goal) { 72 int x = path[n - 1]; 73 if (x == goal) { 74 store_path(n); //print_path(n); 75 } else { 76 for (int i = 0; i < M; i++) { 77 int y = adjacent[x][i]; 78 if (y == 0) break; 79 if (!visited[y]) { 80 path[n] = y; 81 visited[y] = true; 82 dfs(n + 1, goal); 83 visited[y] = false; 84 } 85 } 86 } 87} 88 89int main(void) { 90 path[0] = A; 91 visited[A] = true; 92 dfs(1, G); 93 sort_and_print(); 94 return 0; 95}

実行結果

plain

1ACEG 2ABCEG 3ABDEG 4ACBDEG

投稿2021/12/15 15:11

編集2021/12/17 08:39
jimbe

総合スコア13209

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

C

1#define SIZE 1000 2 3int path2[SIZE][N]; 4int idx[SIZE]; 5int size = 0; 6 7void add(int n) 8{ 9 int i; 10 path2[size][0] = n; 11 for (i = 0; i < n; i++) path2[size][i+1] = path[i]; 12 for (i = size; i > 0 && path2[idx[i-1]][0] > n; i--) 13 idx[i] = idx[i-1]; 14 idx[i] = size++; 15} 16 17void print_all(void) 18{ 19 for (int i = 0; i < size; i++) { 20 int k = path2[idx[i]][0]; 21 for (int j = 1; j <= k; j++) 22 printf("%c ", path2[idx[i]][j] + 'A' - 1); 23 putchar('\n'); 24 } 25}

このコードを int path[N]; より後に追加し、
dfs関数の中の、print_path(n);add(n); に変更し、
main関数の dfs(1, G); の後に print_all(); を追加してみてください。

投稿2021/12/15 11:43

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問