C言語で2部グラフのマッチングを求めるプログラムを利用してラテン方陣を書きたいのですが、マッチングする行をfor文で回せばいいということがわかるのですが、マッチングしたものを保存して、再度マッチングさせるのがどうすれば上手く行くのかわかりませんでした。プログラムは6×6行列です。またマッチングしたものを最後行列として表示する方法についても悩んでいます。
下記は1つの2部グラフマッチングを求めるプログラムです。
一番下は元のプログラムで、教えてもらったもので
0123 4 5
67891011の点でのマッチングを表しています。
ですが配列内の動きを見たかったと、少しマッチングしたものが見にくかったので表示を
123456
123456の点として表示を考えたのが上のプログラムです。
方法としては
2部グラフでのマッチングを求めるプログラムですので、マッチングした下の点を保存して、上の点として扱い再度マッチングすべきもとの点を探す様にしたいです。
さらに要領としては回目は1={2,3,4,5,6}の点とマッチングが可能で2を選んだ場合2回めでは2={3,4,5,6}の点から選べるという様に1回ずつ各点が選べる回数が減っていけば最終的に決定すると考えられます。なので、はじめは上の一つの点から自身を除いた全ての点にパスが出ている状態から、回数を重ねるごとにパスが減っていく様にすれば自然とラテン方陣としてできると考えられます。
例えば
12345で作った場合で、2行目で
54231となった場合
54231の結果を元にマッチングを行い
31452とマッチングさせる
という様にすれば
求めたい行の回数分行う事によってラテン方陣ができると思います。
最終的には
12345
54231
31452
45123
23514
というような形に表示をしたいです。
教えてくださる方がいたらよろしくお願いします。
コード #include <stdio.h> #include <stdlib.h> #define V 12 #define L_IDX 6 int A[V][V]; int MV[V]; int P[V]; int aug(int, int *); int main(){ int i, j, p, q, r; int find; r=V/2; for(i=0;i<V;i++){ for(j=0;j<V;j++){ A[i][j] = 0; } } /* A[0][6] = 1, A[0][7] = 1; A[1][6] = 1, A[1][7] = 1; A[2][6] = 1, A[2][7] = 1; A[3][5] = 1, A[3][6] = 1; A[4][5] = 1, A[4][7] = 1, A[4][8] = 1, A[4][9] = 1; */ A[0][6] = 1, A[0][7] = 1; A[1][6] = 1, A[1][7] = 1, A[1][9] = 1; A[2][6] = 1, A[2][7] = 1, A[2][8] = 1; A[3][8] = 1, A[3][9] = 1, A[3][10] = 1; A[4][8] = 1, A[4][9] = 1, A[4][11] = 1; A[5][10] = 1, A[5][11] = 1; for(i=0;i<V;i++){MV[i] = 0;} find = 1; while(find){ find = 0; for(i=0;i<V;i++){P[i] = 0;} for(i=0;i<L_IDX;i++){ if(MV[i]==0){ P[i] = 1; find = aug(i,P); if(find){ //*********************************************************** for(p=0;p<V;p++){ for(q=0;q<V;q++){ if(q%r==0)printf("|"); printf("%2d",A[q][p]); } printf("\n"); } printf("+++++++++++++++++++++++++++\n"); printf("\n"); //*********************************************************** MV[i] = 1; break; } P[i] = 0; } } } for(i=r;i<V;i++){ for(j=0;j<r;j++){ if(A[i][j]==1){ printf("A[%d][%d]=%d ",i%6+1,j,A[i][j]);} //マッチングしてる箇所を表示 } } printf("\n"); for(i=r;i<V;i++){ for(j=0;j<r;j++){ if(A[i][j]==1){ printf("%3d",j);//マッチング後を表示 } } } } int aug(int v, int P[]){ int i,j,k; int find,v1,v2; for(j=0;j<V;j++){ if(A[v][j]==1&&P[j]==0){ P[j] = 1; find = aug(j,P); if(find==1){ //found augmenting path A[v][j] = 0, A[j][v] = 1, MV[j] = 1; return(1); } P[j] = 0; } }// end for j if(v>=L_IDX&&MV[v]==0){ return(1); // found augmenting path }else{ return(0); // could not find augmenting path } }
元のプログラム
コード #include <stdio.h> #include <stdlib.h> #define V 12 #define L_IDX 6 int A[V][V]; int MV[V]; int P[V]; int aug(int, int *); int main(){ int i, j, p, q; int find; for(i=0;i<V;i++){ for(j=0;j<V;j++){ A[i][j] = 0; } } /* A[0][6] = 1, A[0][7] = 1; A[1][6] = 1, A[1][7] = 1; A[2][6] = 1, A[2][7] = 1; A[3][5] = 1, A[3][6] = 1; A[4][5] = 1, A[4][7] = 1, A[4][8] = 1, A[4][9] = 1; */ A[0][6] = 1, A[0][7] = 1; A[1][6] = 1, A[1][7] = 1, A[1][9] = 1; A[2][6] = 1, A[2][7] = 1, A[2][8] = 1; A[3][8] = 1, A[3][9] = 1, A[3][10] = 1; A[4][8] = 1, A[4][9] = 1, A[4][11] = 1; A[5][10] = 1, A[5][11] = 1; for(i=0;i<V;i++){MV[i] = 0;} find = 1; while(find){ find = 0; for(i=0;i<V;i++){P[i] = 0;} for(i=0;i<L_IDX;i++){ if(MV[i]==0){ P[i] = 1; find = aug(i,P); if(find){ //*********************************************************** for(p=L_IDX;p<V;p++){ for(q=0;q<L_IDX;q++){ printf("%d ",A[p][q]); } printf("\n"); } printf("++++++++++++++++++++++++++\n"); //*********************************************************** MV[i] = 1; break; } P[i] = 0; } } } for(i=L_IDX;i<V;i++){ for(j=0;j<L_IDX;j++){ if(A[i][j]==1){ printf("A[%d][%d]=%d ",i,j,A[i][j]);} } } printf("\n"); } int aug(int v, int P[]){ int i,j,k; int find,v1,v2; for(j=0;j<V;j++){ if(A[v][j]==1&&P[j]==0){ P[j] = 1; find = aug(j,P); if(find==1){ //found augmenting path A[v][j] = 0, A[j][v] = 1, MV[j] = 1; return(1); } P[j] = 0; } }// end for j if(v>=L_IDX&&MV[v]==0){ return(1); // found augmenting path }else{ return(0); // could not find augmenting path } }
