追記(2007/06/24)

ダイクストラ法の復習をしました。以下に書いてあるのは全然ダイクストラ法じゃないということが判明しました。とっぺんぱらりのぷう
一応書き直してみた。けどなんつうか、問題例がいいかげん過ぎて参考にはならないような。「#define EDGECOST 1」とか。普通はこの部分が色々な値になる。

ダイクストラ法をC言語で。

なんか最近微妙にまわりでダイクストラ法がブームらしいので、C言語で書いてみる。つっても、汎用的な書き方ってのをどうやるかは知らないんだけど。大学の同級生とか後輩とかがプログラムで迷路を解く課題に苦しめられたらしいので、俺的理解のダイクストラ法で迷路を解いてみる。

コードが長くなっちゃうんで、問題となる迷路はコードに埋め込みでこんな5×5のcharで与える。sがスタート地点、gがゴール地点、0が通路で1が壁を意味する。斜め移動は無し、地点間のコストは全て1。
(文字列末尾の '\0' 入れると長さ6の char だけど気にしない)

	char *route_dat[] = {
		"s0001",
		"10100",
		"00000",
		"01011",
		"0000g"
	};

ほんでまあ、この元となる経路データ route_dat から、最短経路を求めるのに適した経路データ構造に変換してからダイクストラ法で解いた。
実行結果はこんな。

% ./dijkstra
(0,0)
(0,1)
(1,1)
(2,1)
(2,2)
(3,2)
(4,2)
(4,3)
(4,4)

うんまあとりあえずこの問題では合ってるらしいよ。

肝心のデータ構造とダイクストラ法を用いた関数はこんな。

struct node{
  char key; // 元々の文字
  int col, row; // 座標
  struct node *link[4]; // リンク
  int linked_count; // このノードからリンクしている数

  int is_shortest; // 既に最短経路か否か
  int cost; // スタート地点からのコスト
  struct node *parent; // このノードの親ノード
};
typedef struct{
  int cols, rows;
  struct node nodes[MAX_COL][MAX_ROW];
  struct node *start, *goal;
} Route;
int relax(Route *route, struct node *curnode){
  int i;
  for(i=0;i<curnode->linked_count;++i){
    struct node *linked = curnode->link[i];
    int newcost = curnode->cost + EDGECOST;
    if(linked->cost > newcost){
      linked->cost = newcost;
      linked->parent = curnode;
    }
  }
  return 1;
}
struct node *nextnode(Route *route){
  struct node *minnode = NULL;
  int i, j;
  for(i=0;i<route->cols;++i){
    for(j=0;j<route->rows;++j){
      struct node *n = &route->nodes[i][j];
      if(!n->is_shortest && (minnode==NULL || minnode->cost > n->cost)){
        minnode = n;
      }
    }
  }
  minnode->is_shortest = 1;
  return minnode;
}
int dijkstra(Route *route, struct node *start, struct node *goal){
  struct node *curnode = start;
  while(curnode != goal){
    relax(route, curnode); // 最短経路がわかった点からパスがある点の更新
    curnode = nextnode(route); // コストが一番小さい点を次の点に
    if(curnode == NULL){
      return 0;
    }
  }
  return 1;
}

ダイクストラ法の実装は適当。ここではいいかげんな二次元配列で実装してますけど、本当は二分ヒープで実装したプライオリティーキューとかでやると良いらしいですよ。

以下全コード。データの変換にわりと行数つかってる。

続きを読む

まあそんなことはあとで考える。

いいかげん月曜提出のレポート終わらせて、次のレポートにとりかかりますよ、と。しかしあれだなあ。だいたい週に2、3個のレポート課題がなんかの講義で出るから、学期終わるまでは常にレポートある状態なんだな。まあ嫌いじゃない。溜めっちまうと辛いけど。今期は順番に消化中。
というわけでいきますか。常微分方程式数値計算レポート書くます。プログラム書くのは直ぐ終わったけど数学的な考察とかに手こずります。まあもうすぐ終わらせる。
次にとりくむレポートは楽しい楽しいコンパイラ数値計算も楽しさ無いわけじゃないけれども。

test