プロが教えるわが家の防犯対策術!

下記のプログラムを改良して2点交叉にしたいのですが、遺伝子アルゴリズムもC++も初心者なので、よくわかりません。どなたかお知恵を貸してください。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "come.h"

int kousa()
{
unsigned int max=100;
unsigned int max2=17;

int a,b,c,d;
int i,v,w,y,n,o,k,p,f;

char kari[1][17];
w=0;//カウンタ
n=0;
srand((unsigned)time(NULL));

for(v=0;v<100;v++)
{
for(i=0;i<17;i++)
{
get[v][i]=next[v][i]; //next[175][17]からget[100][17]へコピーする(親)
}
}

for(o=0;o<100;o++)
{
for(k=0;k<17;k++)
{
take[o][k]=next[v][k]; //next[175][17]からtake[100][17]へコピーする(子)
}
}
for(d=0;d<50;d++)
{
a=(rand()%max); //1つ目の交叉する列を見つける
b=(rand()%max); //2つ目の交叉する列を見つける
c=(rand()%max2); //交叉ポイント見つける

for(;c<17;c++) //1点交叉
{
kari[n][c]=get[a][c];
get[a][c]=get[b][c];
get[b][c]=get[n][c];
}
for(y=0;y<17;y++)
{
take[w][y]=get[a][y]; //get[100][17]からtake[50][17]へコピー
take[w+1][y]=get[b][y];
}
w=w+2;
}
for(p=0;p<100;p++)
{
for(f=0;f<17;f++)
{
next[nextpop][f]=take[p][f];
}
nextpop++;
}
return 0;
}

A 回答 (2件)

恐れ入ります。

No.1で回答したものです。

>回答のプログラムを直接入力すると、kari[i] = get[father][i];の所で「左のオペランドが、左辺値になっていません」、というエラーが起きるので、変数iの部分がどう変えればいいか教えてもらえませんか?

参考にしていただいて、自身で作り直していただくのが一番なのですが、
追加で回答しておきます。
できるだけ元々のソースを残したまま、追加・修正しました。
(追加した部分は、ソース内にコメントを入れました。元ソースと比較して、何をしているか考えてみて下さい)

なお、再度繰り返しますが掲載されたソースが「部分抜粋」で、「ソース全て」ではありません。全て載せていただけなければ、これ以上は判断が付きかねます。
(どんなプログラムの一部なのか推測するしかないので、弄りようがないです)
動かなかった場合は、全てのソースをおみせ願えないでしょうか。


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "come.h"

int kousa()
{
unsigned int max=100;
unsigned int max2=17;

int a,b,c,d;
int father, mother, point_1, point_2, temporary;/* 2点交叉で使う変数 */
int i,v,w,y,n,o,k,p,f;

char kari[1][17];
w=0;//カウンタ
n=0;
father = mother = point_1 = point_2 = temporary = 0; /* 初期化 */
srand((unsigned)time(NULL));

for(v=0;v<100;v++)
{
for(i=0;i<17;i++)
{
get[v][i]=next[v][i]; //next[175][17]からget[100][17]へコピーする(親)
}
}

for(o=0;o<100;o++)
{
for(k=0;k<17;k++)
{
take[o][k]=next[v][k]; //next[175][17]からtake[100][17]へコピーする(子)
}
}
for(d=0;d<50;d++)
{
father = (rand() % max); /* 1つめの交叉する列を見つける */
mother = (rand() % max); /* 2つめの交叉する列を見つける */
point_1 = (rand() % max2); /* 交叉ポイントを見つける */
point_2 = (rand() % max2); /* 交叉ポイントを見つける */
/*↓から2点交叉*/
for(i = 0; i < 17; i++) {
if (i < point_1) {
temporary = get[father][i];
get[father][i] = get[mother][i];
get[mother][i] = temporary;
}
if (i < point_2) {
temporary = get[father][i];
get[father][i] = get[mother][i];
get[mother][i] = temporary;
}
}
/* ↑まで2点交叉 */

for(y=0;y<17;y++)
{
take[w][y]=get[a][y]; //get[100][17]からtake[50][17]へコピー
take[w+1][y]=get[b][y];
}
w=w+2;
}
for(p=0;p<100;p++)
{
for(f=0;f<17;f++)
{
next[nextpop][f]=take[p][f];
}
nextpop++;
}
return 0;
}
    • good
    • 0

恐れ入ります。



ざっと読みましたが、質問に掲載されたプログラムが部分抜粋のようですので、不明点が多いです。推測して回答します。

遺伝的アルゴリズムの基礎はご存じですか?

質問に掲載されたプログラムは
・100の個体で、遺伝子数は17。(遺伝子の中身は不明)
・100の個体を、ランダムに50ペア選び交叉させる。
・交叉後、親の個体は保持されない。子が親に取って代わる。
・親集団は交叉中に変化する。親集団は全て破棄され、子が生まれる度に次集団にコピーされる。
# 1点交叉の get[b][c]=get[n][c];は、get[b][c]=kari[n][c];の間違いかと思いますがどうでしょうか?

通常遺伝的アルゴリズムと呼ばれているモノからすると、かなり変則的なアルゴリズムになっています。一度参考書などで確認された方がよろしいかと思います。

上記のプログラムのまま、2点交叉にしたいだけでしたら簡単です。
1点交叉は
親A 00000
親B 11111
の時に、
子C 11000
子D 00111
のようになります。

2点交叉は
親A 00000
親B 11111
の時に、
子C 11001
子D 00110
のように、交換場所が2カ所になるだけです。
つまり

father = (rand() % max);
mother = (rand() % max);
point_1 = (rand() % max2);
point_2 = (rand() % max2);

for(i = 0; i < 17; i++) {
if (i < point_1) {
kari[i] = get[father][i];
get[father][i] = get[mother][i];
get[mother][i] = kari[i];
}
if (i < point_2) {
kari[i] = get[father][i];
get[father][i] = get[mother][i];
get[mother][i] = kari[i];
}
}

これで、point_1かつpoint_2の場合には2回交換して元に戻ることで、2点交叉が実現できます。(もっとエレガントな方法もありますが、理解しづらくなってしまいますので。ご自身でお考え下さい)

変数名の名前の付け方や、冗長部分のまとめ方などは、参考書を参考にしながらご自身でなされた方がよいかと思います。

この回答への補足

回答のプログラムを直接入力すると、kari[i] = get[father][i];の所で「左のオペランドが、左辺値になっていません」、というエラーが起きるので、変数iの部分がどう変えればいいか教えてもらえませんか?

補足日時:2008/01/14 20:37
    • good
    • 0
この回答へのお礼

お礼が遅くなって申し訳ありません。とても参考になりました。

お礼日時:2008/01/14 20:37

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!