/* graph.h : グラフアルゴリズム関数定義部 Shift-JIS コードに変換して cygwin で compile すると通らないことがある K. Shiota 2005.5.31 着手 2005.7.15 version */ #include #include #include /* デフォルトの最大頂点数 */ /* Segmentation fault のエラーが出るときは MAXORDER の値を小さくせよ インクルード元でも #define で設定できる */ #ifndef MAXORDER #define MAXORDER 256 #endif #define min(x,y) ( x < y ? x : y ) #define max(x,y) ( x > y ? x : y ) /* グラフを表す構造体の定義 */ /* ord = 頂点数と、隣接行列 adj[][] で表す */ /* メモリ節約のため隣接行列の成分を char 型に変更 (2005.6.10) */ typedef struct { int ord; char adj[MAXORDER][MAXORDER]; } Graph; /********** リスト操作関数定義部 **********/ /* リストを表す構造体の定義 */ /* len = 長さと、メンバー mem[] で表す */ typedef struct { int len; int mem[MAXORDER]; } List; /* リスト s 内に k が存在するときは 1、そうでないときは 0 を返す */ int ListMemberQ(int k, List s) { int i; for(i=0; ii;j--) if(t.mem[j]v){ t=u; u=v; v=t; } for(i=0;i255){ printf("最大重みは 255 までにしてください。\n"); exit(1); } g=EmptyGraph(n); for(i=0;i0 && !ListMemberQ(i,cl)){ // 現在の探索点の隣接点で未探索の点を探し見つかれば p->mem[i]=c; // 親を登録 t.adj[i][c]=1; // 探索木の辺を登録 t.adj[c][i]=1; // 探索木の辺を登録 cl.mem[cl.len++]=i; // 探索済みリストに登録 c=i; // 現在点を i に進める b=0; // バックトラックは不要 break; } } if(b){ // バックトラックが必要なとき // 現在点が r ならこれ以上の探索は不可能 // そうでなければ探索点の親へ戻る if(c==r) f=1; else c=p->mem[c]; } }while(cl.len!=g.ord && !f); // 全ての点を探索し終わったか、探索続行不可能で終了 return t; } /* グラフ g を根 r から広さ優先探索する */ /* p : 親 ( parent ) を登録するリスト */ /* 返り値は広さ優先探索木 */ Graph WFSTree(Graph g, int r, List *p) { Graph t; // 最終的に広さ優先探索木を格納して返り値にする List ll; // 各 node のレベルを登録するリスト int c; // 現在の探索点 ( current node ) int f; // 連結成分を探索し終わったか否か ( finish ) int l=0; // 現在のレベル int i,j; t=EmptyGraph(g.ord); // 木の初期化 *p=ListInitialize(g.ord,-1); // 親が居ないと -1 ll=ListInitialize(g.ord,-1); // r 以外の点のレベルの初期値は -1 ll.mem[r]=l; do{ f=1; for(c=0;c0 && ll.mem[i]==-1){ // 現在の探索点の隣接点で未探索の点を探し見つかれば p->mem[i]=c; // 親を登録 t.adj[i][c]=1; // 探索木の辺を登録 t.adj[c][i]=1; // 探索木の辺を登録 ll.mem[i]=l+1; // レベルを l+1 に設定 f=0; // 探索続行可能 } } } } l++; // レベルを +1 }while(ListMemberQ(-1,ll) && !f); // 全ての点を探索し終わったか、探索続行不可能で終了 return t; } /*********** グラフ変形関数定義部 **********/ /* Graph g の、部分頂点リスト v から誘導される部分グラフを返す ( v は若い番号順と仮定 ) */ Graph InducedSubGraph(Graph g, List v) { Graph h=g; int i; for(i=g.ord-1;i>=0;i--) if(!ListMemberQ(i,v)) h=RemoveVertex(h,i); return h; } /* グラフ g から多重辺とループを取り去ったグラフを返す */ Graph SimplifiedGraph(Graph g) { Graph h=g; int i,j; for(i=0;i0){ h.adj[i][j]=1; h.adj[j][i]=1; } } return h; } /*********** 分解 **********/ /* Graph g を連結成分に分解する */ /* 返り値は連結成分の個数 k, ni=o->mem[i] は第i連結成分の頂点数 si=s->mem[i] は n0,...,n{i-1} の積算 v->.mem[si],...,v->mem[si+ni-1] は第i成分の頂点リスト */ int ConnectedDecompose(Graph g, List *o, List *s, List *v) { Graph t; List p; int r,i,j,k=0; o->len=0; s->len=0; v->len=0; while(v->lenlen,*s); // インデックスを登録 r=0; while(ListMemberQ(r,*v)) r++; // 未登録点 r を検索 t=WFSTree(g,r,&p); // r を根とする広さ優先探索を実行 i=0; for(j=0;jmem[i] は第iブロックの頂点数 si=s->mem[i] は n0,...,n{i-1} の積算 v->.mem[si],...,v->mem[si+ni-1] は第iブロックの頂点リスト */ /* Reference: Chartrand-Oellermann, Applied and Algorithmic Graph Theory, Alg.3.2 */ int BlockDecompose(Graph g, List *o, List *s, List *v) { Graph sc=g; // scan した辺を除去してゆく List pr; // parent List lp; // low point List df; // depth first search index List ss; List u; int c,r,i=0,j,k=0; // BlockDecompose_Step1 pr=ListInitialize(g.ord,-1); df=ListInitialize(g.ord,0); o->len=0; s->len=0; v->len=0; ss.len=0; BlockDecompose_Step2: for(j=0;j=g.ord) return k; else{ c=j; // current vertex r=j; // root } BlockDecompose_Step3: i++; df.mem[c]=i; lp.mem[c]=i; ss=Prepend(c,ss); BlockDecompose_Step4: for(j=0;jlen,*s); // インデックスを登録 *v=ListAdd(*v,u); // 頂点を登録 *o=Append(u.len,*o); // 頂点数を登録 k++; // ブロック数を更新 ss=SubList(ss,j+1,ss.len-1); } // BlockDecompose_Step10 c=pr.mem[c]; goto BlockDecompose_Step4; } // BlockDecompose_Step11 for(j=0;jlen,*s); // インデックスを登録 *v=ListAdd(*v,u); // 頂点を登録 *o=Append(u.len,*o); // 頂点数を登録 k++; // ブロック数を更新 ss=SubList(ss,j+1,ss.len-1); BlockDecompose_Step12: for(j=0;j0){ h=RemoveEdge(h,c,j); c=j; p=Append(c,p); break; } }while(!v.mem[c]); j=0; while(p.mem[j]!=c) j++; return SubList(p,j,p.len-1); } /* 頂点数 n のグラフの中の、巡回リスト c で与えられた閉路を返す */ Graph ListtoCycle(int n, List c) { Graph g=EmptyGraph(n); int i; for(i=0;i0) s=Append(i,s); return s; } /* Graph g が空グラフであるか否かを判定する */ int EmptyGraphQ(Graph g) { return (CountEdge(g)==0); } /* グラフ g の辺 uv が橋であるか否かを判定する */ int BridgeQ(Graph g, int u, int v) { Graph t; List p; t=WFSTree(RemoveEdge(g,u,v),u,&p); // g から uv を除去したグラフで u を根とする wfs を実行し return (p.mem[v]==-1); // v に親がいなければ uv は橋 } /* グラフ g が連結であるか否かを判定する */ int ConnectedQ(Graph g) { Graph t; List p; int i; t=WFSTree(g,0,&p); // g で 0 を根とする wfs を実行し for(i=1;i0 && h.adj[i][j]0){ t=-1; // 橋による隣接点登録用変数 b=0; // 橋以外の隣接点があれば 1 for(i=0;i0){ if(!BridgeQ(h,c,i)){ // ci が橋でなければ i へ進む h=RemoveEdge(h,c,i); r--; ec[k++]=i; // サーキットに i を登録 c=i; // 現在位置を i に更新 b=1; // 橋以外の隣接点があった break; } else{ if(t==-1) t=i; // ci が橋のときは t=i を仮登録 } } } if(b==0){ h=RemoveEdge(h,c,t); r--; ec[k++]=t; // サーキットに t を登録 c=t; // 現在位置を t に更新 } } return m; } /* グラフ g が半オイラーグラフであるか否かを判定する */ /* オイラーでない半オイラーのとき真、そうでないとき偽 奇数次数の2点を ポインタで返す */ int SemiEulerianGraphQ(Graph g, int *u, int *v) { int i,j,x,c=0; if(!ConnectedQ(g)) return 0; // 連結でなければ偽 for(i=0;i2) return 0; // 奇数次数の点が3個以上あれば偽 } } if(c==0) return 0; else return 1; } /* 半オイラーグラフ g の半オイラー歩道を配列で返す */ /* 返り値は g のサイズ 奇数次数の2点 u,v は引数で受け取る */ int SemiEulerianWalk(Graph g, int u, int v, int *ew) { int ec[1024],m,i,j; m=EulerianCircuit(AddEdge(g,u,v),ec); for(i=0;i0) nb.mem[k++]=i; // 探索点の未昇格な隣接点を検索 nb.len=k; for(j=0;j=0){ el.mem[j]=tl.mem[j]; // j の仮ラベルを永久ラベルに昇格し c=j; // j を次の探索点に } }while(j>=0 && c!=v); if(c==v){ *p=ParentPath(pt,u,v); return el.mem[v]; } else{ // printf("There is no %d-%d path.\n"); return -1; } } /*********** ネットワークフロー **********/ /* ランダムなネットワークを返す */ /* 頂点数 = n, 弧の割合 = rate/2, 最大重み = m ( m<=255 に限定 ) u = 入口、v = 出口、ループはなし */ Graph RandomNetwork(int n, int u, int v, float rate, int m) { Graph g; int i,j; float r; if(m>255){ printf("最大重みは 255 までにしてください。\n"); exit(1); } g=EmptyGraph(n); for(i=0;iadj[ph.mem[i-1]][ph.mem[i]])+=m; (r.adj[ph.mem[i-1]][ph.mem[i]])-=m; (r.adj[ph.mem[i]][ph.mem[i-1]])+=m; } t=WFSTree(r,u,&pr); } for(i=0;iadj[i][j]>mf->adj[j][i]){ mf->adj[i][j]-=(mf->adj[j][i]); mf->adj[j][i]=0; } else{ mf->adj[j][i]-=mf->adj[i][j]; mf->adj[i][j]=0; } vl=0; for(i=0;iadj[u][i]; return vl; }