###前提・実現したいこと
遺伝的アルゴリズムでナップザック問題を解こうとしてます。
しかし遺伝的アルゴリズムをプログラムするのは初めてだし、
プログラムが正しいか自信がないのでわからないところを質もします。
Visual Studio 2015でやりました。
###発生している問題・エラーメッセージ
エラーはでていませんが、実行して「初期集団決め→評価→選択→交叉→変異→評価→・・・」
の順にやっているんですが、実行結果を見ると所々で値が小さくなったりしてます。
これは問題ありということでしょうか?
例えば5世代目の値が「価:174」なのに6世代目になると「価値:150」みたいに落ちているということです。
###該当のソースコード
C言語とC++を併用してコーディングしました。交叉のところは一点交叉で行いました。
またそれ以外の欠陥、改善点があったらどうか教えてください。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <ctime>
using namespace std;
const int N = 100; //ナップザックの容量
const int M = 30; //品物の数
const int MAN = 10; //子孫の数
int Child[MAN][M]; //子孫の遺伝子情報
int Kati[MAN]; //子孫のそれぞれの価値
int Ryou[MAN]; //子孫のそれぞれの容積
//ナップザックに入れる物の情報。価値と大きさ
struct Mono {
int Money;
int ryou;
};
Mono mono[M];
void init(); //初期集団を決める
void hyoka(); //それぞれの個体の価値を集計
void sentaku(int *oya); /集団から次の世代を作るための親を決める。
引数のoya配列には親の添え字を保存する/
void Sex(int *oya); //sentaku関数で選んだ親から子孫を作る
void heni(); //突然変異を起こす
void show(); //それぞれの価値と大きさを表示
int main()
{
init();
hyoka();
int oya[2]; for (int i = 0; i < 1000; i++) { sentaku(oya); Sex(oya); heni(); hyoka(); show(); } return 0;
}
void init()
{
//価値と大きさはランダムで決める
srand((unsigned int)time(NULL));
for (int i = 0; i < M; i++) { mono[i].Money = rand() % 20 + 1; mono[i].ryou = rand() % 10 + 1; } cout << "価値: "; for (int i = 0; i < M; i++) { cout << mono[i].Money << ","; } cout << endl; cout << "大きさ: "; for (int i = 0; i < M; i++) { cout << mono[i].ryou << ","; } cout << endl; for (int i = 0; i < MAN; i++) { for (int j = 0; j < M; j++) { Child[i][j] = rand() % 2; } }
}
void hyoka()
{
for (int i = 0; i < MAN; i++) { Kati[i] = 0; Ryou[i] = 0; } int sum = 0; for (int i = 0; i < MAN; i++) { for (int j = 0; j < M; j++) { if (Child[i][j] == 1) { sum += mono[j].ryou; if (sum > N) { Kati[i] = 0; break; } else { Kati[i] += mono[j].Money; Ryou[i] += mono[j].ryou; } } } sum = 0; }
}
//ルーレット方式で親を決定する
void sentaku(int* oya)
{
int total = 0;
for (int i = 0; i < MAN; i++) {
total += Kati[i];
}
int k = 0; int kazu = 0; int kazu2 = 0; for (int i = 0; i < 2; i++) { //同じ親を選ばないように同じなら別を選ぶようにする while (kazu == kazu2) { kazu = rand() % total; } kazu2 = kazu; for (int j = 0; j < MAN; j++) { //ルーレットなので乱数より大きくなったらその遺伝子を親にする if (kazu < Kati[j]) { //親の遺伝子がある配列の添え字を保存 oya[k] = j; k++; break; } } }
}
void Sex(int *oya)
{
for (int i = 2; i < MAN; i += 2) {
/一点交叉する境界をランダムに求める。
その境界をもとに子孫を2人作る/
int line = rand() % M + 2;
for (int j = 0; j < line; j++) {
Child[i][j] = Child[oya[0]][j];
}
for (int j = line; j < M; j++) {
Child[i][j] = Child[oya[1]][j];
}
for (int j = 0; j < line; j++) {
Child[i + 1][j] = Child[oya[1]][j];
}
for (int j = line; j < M; j++) {
Child[i + 1][j] = Child[oya[0]][j];
}
}
}
void show()
{
cout << "価値: ";
for (int i = 0; i < MAN; i++) {
cout << Kati[i] << ",";
}
cout << endl;
cout << "量: "; for (int i = 0; i < MAN; i++) { cout << Ryou[i] << ","; } cout << endl; int max = Kati[0]; int ryou = Ryou[0]; for (int i = 1; i < MAN; i++) { if (max < Kati[i]) { max = Kati[i]; ryou = Ryou[i]; } } cout << "(" << max << "," << ryou << ")" << endl;
}
void heni()
{
for (int i = 0; i < MAN; i++) {
int kazu = rand() % 100;
if (kazu < 3) {
int kazu2 = rand() % M;
Child[i][kazu2] = (Child[i][kazu2] + 1) % 2;
}
}
}
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。