質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

6597閲覧

Cでナップザック問題を遺伝的アルゴリズムで解くときに問題がありました。

wanntinntyann

総合スコア12

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/04/14 13:37

###前提・実現したいこと
遺伝的アルゴリズムでナップザック問題を解こうとしてます。
しかし遺伝的アルゴリズムをプログラムするのは初めてだし、
プログラムが正しいか自信がないのでわからないところを質もします。
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;
}
}
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

値が一度小さくなるのは親世代での最適値がうまくコピーされてないからだと思います。自分がよく使うGAは
1.配列にランダムデータ作成
2.評価
3.評価の良い順で一定確率Aで配列内に適宜コピー
4.一定確率Bで交差
5.一定確率Cで突然変異
6.2.に戻る
こんな感じです。A,B,Cのパラメータ変えると収束率が変わります。整数型の最適化問題では解の空間が滑らかではないので局所最大化問題とは別に、局所の山に崖があって、崖から転げ落ちる状態が発生します。現状では前世代での最適な遺伝子が(交差や突然変異で)死亡するので解の値が悪くなっています。つまり死亡率が高いので要素の数を増やし優秀な遺伝子が生き残る確率を上げたほうがいいでしょう。
すごく単純な解決としては前回最適な値を無傷で次世代に残したら解が後退することはないですね。

投稿2016/04/15 00:33

pochi0701

総合スコア210

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Priceの要素を全部を足したものをTotalとし、
0-Totalからランダムで値を取っていますが、
それをPriceの個別の要素と比較していますね。

この状態では、殆どの確立でif文内部を通りません。
よって、oya配列に親となるはずの要素番号は入らず、
oya配列の初期化されていない値で、配列にアクセスすることになります。

また、一度でもif文内を通った場合においても同様に、
前の親として使われた要素番号がそのまま使われるということが起こり、
意図した挙動とは違う挙動になっていると思います。

投稿2016/04/14 16:08

QQQB

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問