横型から縦型への変換

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら

横型から縦型への変換

#1

投稿記事 by » 15年前

今、横型探索から縦型探索に書き換えているんですが…
どう書き換えたらよいかわかりません。

すみませんが…誰か教えていただけないでしょうか??

横型のプログラムです。
ちなみに言語はC言語です。

int main( void )
{
struct Cell start_state;
struct Cell open_list;
struct Cell closed_list;
struct Cell *temp;
struct Cell *s;
int i,j;

/* リストの初期化(空リストにする)*/
open_list.prev = open_list.next = &open_list;
closed_list.prev = closed_list.next = &closed_list;
start_state.prev = start_state.next = &start_state;

/* 初期状態の設定 */
start_state.state.wolf = 0;
start_state.state.goat = 0;
start_state.state.cabbage = 0;
start_state.state.man = 0;

/* OpenList に初期状態を追加 */
push_back( &open_list, &start_state );

j=0;
/* OpenList が空になるまで、以下を繰り返し実行 */
while( open_list.next != &open_list ) {
j++;
/* OpenList の先頭から状態を一つ取り出す */
s = open_list.next;

/* 途中経過を表示 */
print_progress( s , &open_list , &closed_list , j );
printf("\n");

/* OpenList からsを削除 */
remove_state( s );

/* ClosedList の末尾に状態 s を追加 */
push_back( &closed_list,s );

/* 目標状態なら結果を出力して終了 */
if ( succeeded(s) ) {
print_result( s, &closed_list );
break;
}

/* 禁止状態なら、状態 s を破棄し次に移る */
if ( failed(s) ) {
printf("%d%d%d%d は禁止状態 \n",
s->state.man, s->state.wolf,
s->state.goat, s->state.cabbage);
continue;
}

for( i=0; i<4 ; i++) {
/* 状態 s に可能なオペレーターを適用 */
switch( i ) {
case 0:
temp = move_man( s ); /* 人を移動 */
break;
case 1:
temp = move_wolf( s ); /* 狼を移動 */
break;
case 2:
temp = move_goat( s ); /* 山羊を移動 */
break;
case 3:
temp = move_cabbage( s ); /* キャベツを移動 */
break;
}
/* OpenListの更新(横型探索)*/
if ( find( &open_list, temp ) == &open_list
&& find( &closed_list, temp ) == &closed_list )
/* OpenList、ClosedListに無ければOpenListの末尾に追加 */
push_back( &open_list, temp );
}
}
return( 0 );
}

Re:横型から縦型への変換

#2

投稿記事 by » 15年前

プログラムは横型で、これを縦型にするために書き換えたいんです。

ookami

Re:横型から縦型への変換

#3

投稿記事 by ookami » 15年前

私がちゃんと読めていないだけかもしれませんが、

Cell というのは晶さんが定義されたクラスで、Listか何かを継承しているのでしょうか。
見た感じ、パスがnextとprevしか無いように見えますが、
縦型か横型かというのは、ノード間が複数のパスで繋がっている場合なのではないでしょうか...?

トンチンカンなことを言っていたらすみません...

Re:横型から縦型への変換

#4

投稿記事 by » 15年前

ookamiさんへ

Cellというのは、私が定義したクラスです。
Listの処理として使っています。
使い方は以下のプログラムです。

/* OpenList、ClosedList */
struct Cell {
struct Cell *next; /* リスト中の次の状態へのポインタ */
struct Cell *prev; /* リスト中の前の状態へのポインタ */
struct Cell *path; /* 親状態を指すポインタ */
struct State state; /* 状態を表す変数 */
};

/* リスト処理 */
/* リストの先頭に追加 */
void push_front( struct Cell *l, struct Cell *n )
{
n->prev = l;
n->next = l->next;
l->next->prev = n;
l->next = n;
}

/* リストの末尾に追加 */
void push_back( struct Cell *l, struct Cell *n )
{
n->prev = l->prev;
n->next = l;
l->prev->next = n;
l->prev = n;
}

/* OpenListから状態を削除 */
void remove_state( struct Cell *n )
{
n->prev->next = n->next;
n->next->prev = n->prev;
}

/* リスト中に同じ状態があるか判定 */
struct Cell *find( struct Cell *l, struct Cell *n )
{
struct Cell *p;
p=l->next;
while ( p!=l) {
if ( p->state.man==n->state.man &&
p->state.wolf==n->state.wolf &&
p->state.goat==n->state.goat &&
p->state.cabbage==n->state.cabbage )
return ( p ); /* 見つかった状態へのポインタを返す */
p=p->next;
}
return ( l ); /* リストの先頭へのポインタを返す */
}

/* 目標状態か判定 */
int succeeded( struct Cell *s )
{
if (s->state.man==1 && s->state.wolf==1
&& s->state.goat==1 && s->state.cabbage==1)
return( 1 );
else
return( 0 );
}

ookami

Re:横型から縦型への変換

#5

投稿記事 by ookami » 15年前

晶さんが「横型検索」とおっしゃっているのは、find関数のことですよね?

見た感じ、Cellクラスは「双方向リスト」なので、やはり、横型検索か縦型検索か、ということにはならないのではないでしょうか。

念のため、言葉の確認を...(いや 私が勘違いしているだけかもしれませんので)
http://ja.wikipedia.org/wiki/%E5%B9%85% ... 2%E7%B4%A2
>幅優先探索
>「横型探索」とも言われる。

↑仰っている「横型検索」は、これですよね?


全体としてどんなことをしようとしていて、
データ構造はどんな感じで(たぶんイラストがあった方がよい)、
どんな問題があるか(問題があるからロジックを変更しようとしているのですよね?)
...あたりを書いてもらえますか?

Re:横型から縦型への変換

#6

投稿記事 by » 15年前

返事遅くなってすみません。
最初の方から説明しますね。
問題は川渡りの問題です。
ある人がオオカミとヤギとキャベツをボートで川の対岸に渡さなければならない。
ボートには人とオオカミ、人とヤギ、人とキャベツ、あるいは人が1人しか乗る場所はない。
また、人がいないとオオカミはヤギをヤギはキャベツを食べてしまう。
みんなで渡りきるにはどう渡ればいいか??

添付は横型探索アルゴリズムをC言語を用いたプログラムです。

この川渡りの問題で縦型探索アルゴリズムになるように書き換えたいんですが…
自分でOpenListの更新の部分を作り替えたらOpenListの更新がうまくできませんでした。

ookami

Re:横型から縦型への変換

#7

投稿記事 by ookami » 15年前

むむむ... なるほど...。

最初は、データ構造とfind関数に着目して、「横型検索などではないのでは」と言ったのですが、
全体を見ると、たしかに「横型検索」になっている気がしてまいりました。
# find関数は、「線形検索」ですね。

確認ですが、

 Cell: 人・狼・ヤギ・キャベツがそれぞれ右にいるか左にいるかという状態を表す要素で、
    かつ、双方向リストのポインタと、親状態へのポインタを持つクラス。

 open_list:すでに見つかった、禁止状態でない(何かが何かを食べない)Cellのリスト

 closed_list:すでに見つかった、禁止状態のCellのリスト

という使い方でよろしいでしょうか。
# Cell のリスト構造がちょっち複雑なんですね。
# 双方向リスト と 木構造を合わせ持っているという...
# で、木構造は結果の表示のみに使っており、
# 探索には関係ないようですね。

「再帰」は使っていいでしょうか?
(使っていいテクニックに制限はありますか?)

ookami

Re:横型から縦型への変換

#8

投稿記事 by ookami » 15年前

...もしかして、

if ( find( &open_list, temp ) == &open_list
&& find( &closed_list, temp ) == &closed_list )
push_back( &open_list, temp );

の、
push_back を push_front に変えるだけでよかったりして^^;
ちゃんと試してないのでアレですが。

Re:横型から縦型への変換

#9

投稿記事 by » 15年前

返事遅くなってすみません。
私もpush_back を push_front に変えることはしたんですが、それだけだと探索が最初の一つしかできなくて…

Re:横型から縦型への変換

#10

投稿記事 by » 15年前

/* OpenListの更新(横型探索)*/
if ( find( &open_list, temp ) == &open_list
      && find( &closed_list, temp ) == &closed_list )
/* OpenList、ClosedListに無ければOpenListの末尾に追加 */
push_back( &open_list, temp );

これは「新しく得られた各状態Pについて、次を実行する。
PがClosedListかつOpenListに無ければ、PをOpenListの末尾に追加する」というプログラムです。

ここを縦型探索にするため、「(1)PがClosedListに入っていない。
(2)OpenListに重複した状態があれば前に追加された方を削除する。
(3)PをOpenListの先頭に追加する」という感じに書き換えたいんです。

使ってはいけないテクニックなどは得にありません。

ookami

Re:横型から縦型への変換

#11

投稿記事 by ookami » 15年前

push_back を push_front に変えると、
以下のような結果になりましたが、
これは期待した結果ではないということでしょうか?

Open List = 0000
Closed List =
1: Testing 0000

Open List = 1001 1010 1100 1000
Closed List = 0000
2: Testing 1001

1001 は禁止状態
Open List = 1010 1100 1000
Closed List = 0000 1001
3: Testing 1010

Open List = 0010 1100 1000
Closed List = 0000 1001 1010
4: Testing 0010


(以下省略)

-- 追記

走査の順番を図にしてみました。
画像

Re:横型から縦型への変換

#12

投稿記事 by » 15年前

はい。
どうやったんですか??

ookami

Re:横型から縦型への変換

#13

投稿記事 by ookami » 15年前

56003 で示されていたソースについて、
56016 で書いたとおり、

if ( find( &open_list, temp ) == &open_list
&& find( &closed_list, temp ) == &closed_list )
push_back( &open_list, temp );

の、
push_back を push_front に変えただけです。
が...
> 私もpush_back を push_front に変えることはしたんですが、
とのことだったので、既に試されているのだろうと思い、
「これは期待した結果ではないということでしょうか?」という...。

えーと。
> 探索が最初の一つしかできなくて
という所が問題なんでしょうか。

Re:横型から縦型への変換

#14

投稿記事 by » 15年前

回答ありがとうございます。
私が他の部分のプログラムもイジってたみたいでした。
ookamiさんの言うとおりにしたら解決できました。
本当にありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る