ナップザック問題で、たとえば、
n=4個の品物で、重さと価値が(w, v) = {(2, 3), (1, 2), (3, 4), (2, 2)}
で、重さの総和W=5を超えないように選んだ時、価値の総和の最大値を求める問題で、答えは、
7(0, 1, 3番の品物を選ぶ)
7(0, 2番の品物を選ぶ)
の2通りありますが、価値の総和の最大値だけでなく、2分木を使って2分木ノードの経路もいっしょに表示させたいのですが、この場合あるノードのleftとright両方が選ばれることになります。これらの情報は2分木を作成したときに、各ノードの情報として、left=0、right=1、both=3などとしてどの枝が選ばれたかを書き込んでおいて、rootから辿るようにしています。
この場合、bothにたどり着いた時点で、leftとrightを順番に再帰的に呼び出すと、後に呼んだ
rightの分岐前までのノードの情報がなくなるので、とりあえず、ベクターにこの情報を入れて
おいて、後から欠落したノードの情報を前の経路のノード情報から埋めて使うようにしているの
ですがかなり大変です。(特に何重にも分岐した場合にも対応しないといけないので。)
とりあえず、作ってみて問題なく表示してくれるようにはなったのですが、このあたり既に
ご経験のある方で、もっと簡単でいい方法があるよという場合はご教示願えたらと思います。
No.7ベストアンサー
- 回答日時:
こんにちは、No.2です。
(何故"プンプン"?)ナップサック問題云々はあまり関係なくて、
要は二分木の複数の経路情報をどうやって保持するかって質問ですね。
> なので、ベクターに入る情報は、
> {(0, 5) (1, 3) (2, 3) (3, 0) (4, 0) (2, 2) (3, 2) (4, 0)}
> になります。
No.6さんの仰るとおり、一つの「ベクター」に複数の経路情報を追加していくのが意味不明です。
以下の様にすれば良いのではないでしょうか。
1.「ベクター」は配列にする、配列の一つの要素に一つの経路情報を保持させる。
2.ノードをルートから辿ってbothのノードになったら其処までの経路情報を一時保管する
ノードに保管場所を設ける
補足での例だと、(1,3)ノードに{(0, 5) (1, 3)}を一時保存
3.leftノードの経路を最後までたどり、取得した経路情報を配列「ベクター」に要素として追加
Vec[0] = {(0, 5) (1, 3) (2, 3) (3, 0) (4, 0)}
4.ノードを戻りbothノードまで戻ったら、一時保存した経路情報{(0, 5) (1, 3)}を取り出す
5.4の経路情報にrightノードを最後までたどった経路情報を追記していく
{(0, 5) (1, 3) (2, 2) (3, 2) (4, 0)}
6、5の経路情報を配列「ベクター」に要素として追加
Vec[1] = {(0, 5) (1, 3) (2, 2) (3, 2) (4, 0)}
これで複数の経路情報が取得できます
Vec[0] = {(0, 5) (1, 3) (2, 3) (3, 0) (4, 0)}
Vec[1] = {(0, 5) (1, 3) (2, 2) (3, 2) (4, 0)}
No.8
- 回答日時:
> ベクターの情報が、{ABCB'C'C''}のように分岐した場合、(分岐図を描いてみてください。
)> 単純にノードに保存すると、{ABC}、{AB'C'}、{B'C"}になってしまいませんか?
最初の質問からそうなのですが
質問者様にしか理解できない表現を説明もなしに使用するのは止めて下さい。
さっぱり分かりません。
だいたい「ベクターの情報」が「分岐」ってなんですか?
> 単純にノードに保存すると、{ABC}、{AB'C'}、{B'C"}になってしまいませんか?
無理矢理解釈して、AとB'がbothノードだと仮定すると
1.ノードAで{A}を一時保存
2.ノードB側をたどり、Vec[0] = {A,B,C}となる
3.ノードAに戻る、一時保存した{A}を取り出す
4.ノードB'へ移動、取り出した{A}にB’を追加→{A,B'}
5.ノードB'で{A,B'}を一時保存
6.ノードC'側をたどり、Vec[1] = {A,B',C'}となる
7.ノードB'に戻る、一時保存した{A,B'}を取り出す
8.ノードC''へ移動、取り出した{A,B'}にC''を追加→{A,B',C''}
Vec[2] = {A,B',C''}
「ベクター」には、ちゃんと経路が保存されます。
Vec[0] = {A,B,C}
Vec[1] = {A,B',C'}
Vec[2] = {A,B',C''}
念の為に書きますが、No.7で書いた2~6の手順も、ここで書いた1~8の動作も再帰関数内の処理になります。
疲れた。
> この方法だとどんな分岐が起こっても、ベクター情報だけから複数のパスが正しく再現できます。
じゃあ、その方法で良いじゃん。
No.6
- 回答日時:
う~ん....
「経路探索」で作った「{(0, 5) (1, 3) (2, 3) (3, 0) (4, 0) (2 2) (3 2) (4 0)}」という「ベクター」だけど
・これはどのような意味を持っていて
・どのように作った
のでしょうか?
単純に複数の「経路」を個別に記憶すればいいだけなのに, 「工夫」して上のような「ベクター」を作ったために却って困っているように見えるなぁ.
No.5
- 回答日時:
どんな 2分木なのかけっきょくよくわからんのだけど, 2分木をたどるだけなら基本的には
再帰
でいいのでは?
もともとの質問文の
「bothにたどり着いた時点で、leftとrightを順番に再帰的に呼び出すと、後に呼んだ
rightの分岐前までのノードの情報がなくなる」
というところで
・どのように「再帰的」に呼び出していて
・「後に呼んだrightの分岐前までのノードの情報がなくなる」がどのような問題なのか (「期待する動作」と「実際の動作」がどのように違うのか)
が具体的に書かれていないのでなんともいいにくいんだけど.
No.2
- 回答日時:
こんにちは
No.1様への補足をみましたが
No.1様の「その「2分木」ではなにをどのように格納しているの?」の補足になっていませんよね。
それが分からなければ、ご質問の回答はできないと思いますよ。
> とりあえず、作ってみて問題なく表示してくれるようにはなったのですが
とのことですので、長くなければ現在動作しているプログラムをご提示された方が良いかもしれませんね。
No.1
- 回答日時:
「2分木を使って2分木ノードの経路もいっしょに表示させたい」というのが, なにをしたいのかさっぱりわからない.
「2分木ノードの経路」ってなに? その「2分木」ではなにをどのように格納しているの?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- SQL Server DBのテーブルの設計ができず困っています。 2 2023/06/29 16:43
- 地図・道路 関西エリアの高速道路について教えてください 1 2022/04/05 13:13
- ヤフオク! 落札者の削除について 4 2023/05/22 14:37
- WordPress(ワードプレス) WordpressでYouTubeの埋め込みができない。 1 2022/10/26 01:08
- 政治 今にして思えば、アメリカの大統領がトランプではなくて、バイデンで良かったですね? 4 2022/06/11 06:10
- Excel(エクセル) Excel関数 情報引用する方法 4 2022/07/31 20:59
- SQL Server ACCESSで表が作りたく、そのためのSQL文や設定方法を教えてください。 1 2022/08/15 12:28
- Access(アクセス) ACSESS初心者です マンション管理をACCESSで出来ないかとチャレンジしています。 リレーショ 3 2022/10/08 11:45
- カスタマイズ(車) いわゆる「テレビキャンセラー」について・・・・・ 7 2022/11/01 20:57
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ルート要素ノードが2個ある場合?
-
あるノードリストに、特定の名...
-
CPUの考え方を教えてください ...
-
昔Winnyってありましたけど、あ...
-
同じタグ名の項目取得
-
TreeViewの再表示のちらつきを...
-
VB6.0ツリービューについて
-
C# TreeView 効率良いノード追...
-
2分探索木の高さを求めるプロ...
-
ノードとは
-
二分木の高さについて
-
VB6.0でDOMを使用して...
-
ツリービューを閉じさせたくない。
-
VB6.0でDOMを使用して...
-
vbsのDOMDocumentで要素のText...
-
TreeViewに重複する値をセット
-
XPathGraphでノードの値を取得...
-
バッチファイルでテキストファ...
-
Excel-VBAでXMLの複数ノードの...
-
XMLで要素が記述された順番に意...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
CPUの考え方を教えてください ...
-
昔Winnyってありましたけど、あ...
-
SNMP リンクダウンとノードダ...
-
ルート要素ノードが2個ある場合?
-
同じタグ名の項目取得
-
ノードとは
-
あるノードリストに、特定の名...
-
TreeView の初期表示について
-
ツリービューのノードをダブル...
-
コンテキストメニュークリック...
-
ノード数とは?
-
XML文書の指定した属性値を持つ...
-
複数のマックPCによる数値計算...
-
C#でtreeviewの指定ノードを選...
-
VB6.0ツリービューについて
-
TreeViewの再表示のちらつきを...
-
VB6.0でDOMを使用して...
-
vbsのDOMDocumentで要素のText...
-
TreeViewで複数ノードの選択は...
-
C# TreeView 効率良いノード追...
おすすめ情報
上の例で言えば、
0->1->3
または0
0->2
みたいな話です。
経路が一位ならrootからノードを辿って表示させればいいだけの話ですが、
経理が複数あった場合、その経路をどうやって表示させるのが一番効率的か?
という話です。
ノードの名前は、root = (i, j) = (0, W) = (0,5)からはじめて、
i番目の品物からその品物を取らなかったか取ったかで、
(1, 5)(leftで品物を取らなかった)、(1, 3)(rightで品物を取った)
というように名前を付けて行っています。
経路探索でとりあえずベクターに
{(0, 5) (1, 3) (2, 3) (3, 0) (4, 0) (2 2) (3 2) (4 0)}
を入れておいて、それを
{(0, 5) (1, 3) (2, 3) (3, 0) (4, 0)}
{(2, 2) (3, 2) (4 ,0)}
の2つに分割して、後の経路に抜けた部分を加えて、
{(0, 5) (1, 3) (2, 3) (3, 0) (4, 0)}
{(0, 5) (1, 3) (2, 2) (3, 2) (4, 0)}
みたいな処理をしています。
DPで書くと、
dp[n][j] = 0
j<w[i] の時、
dp[i][j] = dp[i+1][j]
j>=w[i] の時、
dp[i][j] = max(dp[i+1][j], dp[i+1][j-w[i]] + v[i])
(ここで、w[i] 及びv[i]は、i番目の品物の重さと価値)
のアルゴリズムで2分木の各ノードにvalue(=dpの値)とdirectionの値を
書き込んでいきます。最終的には、root=(0, 5)のvalueの値がmax valueになります。
あとは、このrootから書き込まれたdirectionの方向を辿っていくだけです。
ちょっと書き方が悪かったかもしれませんが、DPは使っていません。
DPと同じアルゴリズムを2分木でやっているということです。
2分木ノードを末端まで作った後で、上に向かってこのアルゴリズムでvalueとdirection
を計算していっています。
この件は、2番目の補足の説明の中で書いています。
rootから辿っていって、directionがbothの場合、最初にleftを
再帰的に呼び出して、続いてrightを呼び出しているだけです。
この場合、right側の欠落情報は(0,5)(1,3)です。
最終的に表示してほしい解は、
{(0, 5) (1, 3) (2, 3) (3, 0) (4, 0)}
{(0, 5) (1, 3) (2, 2) (3, 2) (4, 0)}
の2つです。
ノードの名前の付け方は補足の2に書いた通りです。
もし単純に、経路が一位に決まるなら、上の場合だと、rootから辿って
(0, 5) (1, 3) (2, 3) (3, 0) (4, 0)
を表示して終わりになります。
でもこの場合は、解は2つ存在してノード(1,3)のdirectionはbothになっています。
なので、上の経路を辿った後に、再びbothの所に戻ってきて(bothの所では単純に
leftに再帰的に分岐させた後、rigthに分岐させるように書いているからです。)
right側の (2, 2) (3, 2) (4, 0)を辿ります。
なので、ベクターに入る情報は、
{(0, 5) (1, 3) (2, 3) (3, 0) (4, 0) (2, 2) (3, 2) (4, 0)}
になります。
これ以上に簡単にやる方法ってありますか?
ベクターの情報が、{ABCB'C'C''}のように分岐した場合、(分岐図を描いてみてください。)
単純にノードに保存すると、{ABC}、{AB'C'}、{B'C"}になってしまいませんか?
私のやり方だと、ベクターに分岐の情報さえあれば、それを
{ABC}
{B'C'}
{C"}
の3つに分割後、
1番目と2番目のベクター情報から2番目に欠落しているAの情報を2番目に加えて、
{ABC}
{AB'C'}
{C"}
同様に2番目と3番目のベクター情報から3番目に欠落しているAB'の情報を2番目に加えて、
{ABC}
{AB'C'}
{AB'C"}
となります。
この方法だとどんな分岐が起こっても、ベクター情報だけから複数のパスが正しく再現できます。
ごめんなさい。
2番目の保存内容が、B'ではなくAB'になるのを見落としていました。
多分どちらの方法でもできると思います。
私のは先にベクターを作ってから、その後配列に入れています。