• ベストアンサー

アルゴリズムの正当性について

線形探索法のアルゴリズムの擬似コードを書いて、そのアルゴリズムの正当性をループ不変式を用いて証明するという課題があります。 擬似コードは以下のような流れにしようと思いますが、この場合成り立つループ不変はどのようなことになりますか? 配列A[a1..an]に対してv=A[i]ならば添字iを、vがAの中になければNILを出力するアルゴリズムです。 for i ←1 to N if A[i] = v return i return NIL

質問者が選んだベストアンサー

  • ベストアンサー
  • PRFRD
  • ベストアンサー率73% (68/92)
回答No.1

ループ開始時にて A[j] ≠ v (j = 1, ..., i-1)  でどうでしょう.

その他の回答 (1)

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.2

 えとですね、「配列A[a1..an]に対してv=A[i]ならば添字iを、vがAの中になければNILを出力する」では(a1およびanとは何者か、という話は別にしても、)何をやりたいんだか曖昧です。というのは、v=A[i]となるiが複数個ある場合にどうしたいのかが明示されていない。  つまり、ご質問はやりたい事、すなわち仕様(output assertion)をきちんと記述出来ていないという所に問題があるんです。これが書けないと、証明すべき命題が定まりません。  仮に、お書きの「疑似コード」こそがまさしくやりたい事なのだとすれば、その意味は「もし(1≦i≦Nかつv=A[i])となるiがあるならばv=A[i]となるiのうち最小のものを出力し、さもなければNILを出力する」ということ。言い換えれば、出力をkとするとき、 (∃j(1≦j∧j<N∧A[j]=v)→(∀j(1≦j∧j<k → A[j]≠v)∧A[k]=v)) ∧ (∀j(1≦j∧j<N→A[j]≠v)→k=NIL)  また、もしも 「配列A[1..N]に対してv=A[i]となるiがあるならばそのようなiのうちのどれかひとつを出力し、vがAの中になければNILを出力する」という話であるならば、 (∃j(1≦j∧j<N∧A[j]=v)→A[k]=v) ∧ (∀j(1≦j∧j<N→A[j]≠v)→k=NIL) というのが仕様です。  いずれの場合もinvariant assertionとして、ANo.1すなわち ∀j(1≦j∧j<i → A[j]≠v) を選ぶのが良さそう。  けれども、その心配をする以前に、証明したい命題がまだ決まっていないんです。

関連するQ&A

  • 疑似言語で表現されたアルゴリズムについて…

    次の疑似言語で表現されたアルゴリズムを処理の概要の条件を満たしかたについて教えてください。 途中までは求められるのですが、(1)~(5)を教えてください。- (処理の概要) 配列Aには学生番号、配列Bには成績が格納されている。同じ添字の位置に対応する学生番号と成績が格納されている。配列の大きさは10件分である。成績の良い順(降順)に学生番号、成績とも並べ替える。 (配列のイメージ(例)) 添字  配列A  配列B      配列A  配列B 1   1001   50      1004  100   2   1002   75      1002  75 3   1003   25      1005  70 4   1004  100      1001  50 5   1005   70      1003  25 ・     ・     ・        ・    ・ ・     ・     ・        ・    ・ (擬似言語)   ・i←1    (1)   ■i<n   |   ・j←i+1   |   ■j≦n   |   |  ↑  (2)   |   |  |・w1←A(j)   |   |  |  (3)   |   |  |・A(j)←A(i)   |   |  |  (4)    |   |  |・A(i)←w1   |   |  |  (5)   |   |  ↓   |   |  ・j←j+1   |   ■   |  ・i←i+1   ■

  • アルゴリズム(2分探索木)の問題について

    2分探索木のアルゴリズムに関する問題について質問させていただきます。 [問題] 集合Sに対する2文探索木とは、ラベルつきの2分木で、 その頂点vにはSのある要素l(v)がラベルとしてつけられている。 l(v)は次の性質を満たす。 1.vの左部分木の頂点uに対して l(u) < l(v) 2.vの右部分木の頂点uに対して l(u) > l(v) 3.Sの任意の要素aに対して l(v) = a となる頂点vはちょうどひとつある。 図はキーワード集合{begin,else,end,if,then}をあらわす2分探索木の例である。 いま、集合Sを表す2分探索木と要素aが与えられているときa∈Sならば"はい"、 そうでなければ"いいえ"を出力するアルゴリズムを考える。 このアルゴリズムは、木の根rについて一回だけ再帰手続きSEARCH(a,r)を呼び出せばよい。 ただし、SEARCH(a,v)はvを根とする部分木中に要素aが含まれているかを判定する。 含まれているときに値"はい"を、そうでなければ値"いいえ"を返す。 ・アルゴリズム procedure SEARCH(a,v): if a = l(v) then return "はい" else if a < l(v) then if vが左の子wを持つ then return SEARCH( ア ) else return "いいえ" else イ 以下の問題に答えよ。 (1) 上のアルゴリズムのア,イを埋めよ。 (2) 上のアルゴリズムを参考にして、集合Sからのデータの削除DELETE(a,S)を考える。 削除すべき要素aが頂点vのラベルであったとする。そのとき次の3つの場合について、行うべき操作を記述せよ。 (i) 頂点vが葉である (ii) 頂点vの子が1個ある (iii) 頂点vの子が2個ある 以上です。 設問(1)は解けました。 答えは ア: a,w イ: a > l(v) then if vが右の子wを持つ then return SEARCH(a,w) else return "いいえ" になるのではないかと思います。 設問(2)についてなのですが、それぞれの場合について、どのような操作をすればよいのかは、 参考書などを読んで理解したのですが、どのように記述したらよいかがわかりません。 長文になってしまい申し訳ないのですが、回答よろしくお願いいたします。

  • アルゴリズム:2分探索の時間計算量

    アルゴリズムの参考書を読んでいて疑問に思ったんですが、教えてください。 /* 2分探索 */ #include <stdio.h> /*--- 要素数nの配列aからkeyと一致する要素を2分探索 ---*/ int bin_search(const int a[], int n, int key) { int pl = 0;/* 探索範囲先頭の添字【1】 */ int pr = n-1;/* 〃  末尾の添字 【2】*/ int pc; /*   〃  中央の添字 */ do { pc = (pl + pr) / 2;/*【3】*/ if (a[pc] == key) /* 探索成功【4】 */ return (pc);/*【5】*/ else if (a[pc] < key)/*【6】*/ pl = pc + 1;/*【7】*/ else /*【8】*/ pr = pc - 1;/*【9】*/ } while (pl <= pr);/*【10】*/ return (-1);/* 探索失敗【11】 */ } のプログラムがありますが、【1】から【11】までの 実行回数と計算量は次のようになるそうですが、    実行回数   計算量  【1】  1       O(1) 【2】  1       O(1) 【3】  logn     O(logn) 【4】  logn     O(logn) 【5】  1       O(1) 【6】  logn     O(logn) 【7】  logn     O(logn) 【8】  logn     O(logn) 【9】  logn     O(logn) 【10】  logn     O(logn) 【11】  1       O(1) なぜ【3】や【4】がlognになるんでしょうか? 詳しく教えてください。 よろしくお願いします。

  • アルゴリズムの勉強法は慣れしかないのでしょうか?

    学校の先生から、アルゴリズムは慣れだ慣れだと言われて、ひたすら問題を解くのですが、なにかしっくりきません。 時々、ここはなんでこういう事をしているのか分からないという所が出てきます。 例えば、基本情報技術者試験平成16年度春期午後のこの問題 http://www.rs.kagu.tus.ac.jp/infoserv/j-siken/H16a2/pm04.html において、擬似言語中の上から13行目の i: a_idx - span_idx , i < b_idx - a_idx , 1 では、教科書どおり?トレースしていくと a_idx - span_idx なんかは始めは0なんで、なぜ0としないでこんな事をやっているのかなあ・・・と頭を抱えてしまいます。 こうしている理由は、次々とループしていくとiの初期値は0でないときも出てくるからかな?とは想像できるのですが、 a_idx も span_idxもそれに伴って変化していくので 、なんでこんな式を使うの??? と頭がごちゃごちゃになってしまいます。 何か法則的なことがある程度はあるような気がするのですが・・・。 ごく初歩的な例で行くと、iは何の変数かといった時にプログラム中にT(i)などとあると、配列の添え字なんだなと分かる、みたいな事です。 どのようにして考えていけばいいのでしょうか? 何か法則みたいなものをご存知の方も、教えていただけないでしょうか? よろしくお願いします。

  • fortranプログラムについての質問です。

    fortranプログラムについての次の問題について質問させてください。 i=1、2、・・・、50に対し(i,a500(i))(i,a2000(i))を次の演算に従い計算せよという問題です。わかりにくいですが 500と2000、さらに次の式のaのあとのnやn+1,n-1などは添字です。 an+1(i)=0.5{an(i+1)+an(i-1)-2.0d0an(i)}+an(i)  (i=2,3,・・・49), (n=1,2,・・・,500,・・・,2000) ただしa1(i)=0.0(i=1,2,・・・,49), a1(50)=1.0, an(1)=0.0, an(50)=1.0 (n=1,2,3,・・・,500,・・・,2000) である。 というものです。自分は添字のnなどについてはプログラム上では無視し、一次元配列aとbを宣言して、「DOループも用いて i=1~49を回してまずa2(これがb)を求め、そのa2(すなわち)を元の漸化式にの右辺に結果を入れ、それを500回と2000回 別々に回す」という操作を考えたのですがうまくいきません。i-1やi+1をどう扱うかや、そもそもこの考え方は合っているのか、 どうするほうが良いのかなどについてアドバイスをいただきたいです。よろしくお願いします。

  • 線形代数の問題です。至急御願いします!

    問1. fA(Aは小さい添字)R^n→R^m,A∈M(m,n;R)が定める線形写像とする。 A=(a1,a2,...,an)(aiはAの第i列) このとき、fAが単射⇔a1,a2,...,anが一次独立を証明せよ。 問2. fA(Aは小さい添字)R^n→R^m,A∈M(m,n;R)が定める線形写像とする。 fAが全射⇔m=rankAを証明せよ。

  • 線形探索について

    C言語の線形探索の課題なんですが 5つの整数を入力して その入力した値からみつけたい値を探索する課題なのですが #include <stdio.h> /*--- 要素数nの配列aからkeyと一致する要素を線形探索 ---*/ int search(const int a[], int n, int key) { int i = 0; while (1) { if (i == n) return (-1); /* 探索失敗 */ if (a[i] == key) return (i); /* 探索成功 */ i++; } } int main(void) { int i, ky, idx; int x[4]; int nx = sizeof(x) / sizeof(x[0]); printf("%d個の整数を入力してください。\n", nx); for (i = 0; i < nx; i++) { printf("x[%d]:", i); scanf("%d", &x[i]); } printf("探す値:"); scanf("%d", &ky); idx = search(x, nx, ky); /* 配列xから値がkyである要素を線形探索 */ if (idx == -1) puts("探索に失敗しました。"); else printf("%dは%d番目にあります。\n", ky, idx + 1); return (0); } ここまではわかるのですが、 x[0]=99 x[1]=99 x[2]=88 x[3]=99 x[4]=22 と入力したときに 99は 1番目に見つかりました 2番目に見つかりました 4番目に見つかりました と出力したいのですがうまくいきません 線形探索で同じ数値を探索するにはどうすればよいのですか?

  • データ構造とアルゴリズムの問題です

    要素数がnである配列aの要素の合計を求めるアルゴリズムのループ端によるフローチャートを完成せよ(後判定繰返し) sum =a[0] i=1; do{sum=sum+a[i]; i++; }while i<n; a[0] → sum 1 → i 後判定繰返し | □→sum; i+1 → i | □ 後判定繰返し □の中を埋めるんですが教えてください

  • アルゴリズム・ネストループ方式って何?

    プログラムの性能改善の課題が出ているのですが、アルゴリズムとしてネストループ方式、もしくはその延長上のものを用いること、とあります。 図書館でアルゴリズム関係の本を見てみたのですがどこにもネストループに関して説明がなく、大変困っています。 プログラム自体は、ファイルを読み込んで、表示させるだけの簡単なものです。 簡単に抜き出すと、 for (i=0;; i++){ if ((st = read_a(fd_name, &name_buf, i)) <=0) break; for (j = 0;; j++){ if ((st =read_a (fd_home,&home_buf ,j)) <= 0) break; if (!strcmp(name_buf.a , home_buf.b)){ printf("%s =%s (%s)\n", name_buf.a, name_buf.c , home_buf.c); } } if (st <0) break; といったものです。 注意事項として、break文を入れる手法を使わないこととあります。 お願いします。ネストループって何でしょう?教えてください。

  • データ構造とアルゴリズムの問題です

    要素数がnである配列aの要素の最大値を求めるアルゴリズムのループ端によるフローチャートを完成せよ(前判定繰返し) max =a[0] i=1; while i<n do{ if(a[i]>max)max=a[i]; i++; } a[0] → max 1 → i 前判定繰返し □ | yes a[i]□max-----| |        □      NO i+1 → i 前判定繰返し □の中を埋めるんですが教えてください