0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ナップザック問題を遺伝的アルゴリズムで解いてみた

Last updated at Posted at 2026-01-10

ナップザック問題を遺伝的アルゴリズムで解いてみました。
参考にさせていただいたサイトはあるのですが、何年も前のことだったので、検索しても見つけることができませんでした。

品物の数:30
最大重量:20億以下
個体数:1000
足切りライン(総価値がこの順位以下の遺伝子は次世代に残さない):100
繰り返し回数(世代数):30

その品物を採用するかしないかを遺伝子としました。
品物が30個あるので、遺伝子は30bitになります。
親遺伝子は上位100の中からランダムに2個選びます。
遺伝子に2か所切断ポイントを設け、たとえば最初の10bitは親1から受け継ぎ、次の10bitは親2から受け継ぎ、最後の10bitは再び親1から受け継ぐという感じです。
また5%の確率で突然変異を起こし、どこか1か所の遺伝子を反転させます。
総重量が20億を超えた場合は、価値をゼロと設定するようにしました。

以下にc++のプログラムと出力結果、このプログラムを30回実行したときの結果を示します。
最初は個体数100で実行したのですが、30回の出力結果のうち約2/3ぐらいの値がゼロになってしまったので、個体数を1000に増やしてやり直しました。

このプログラムを30回実行した時の結果
total weight = 1910747977    total value = 6464034476
total weight = 1868897366    total value = 6149837764
total weight = 1956576401    total value = 6598594667
total weight = 1946821635    total value = 6654768552
total weight = 1979202615    total value = 6062806162
total weight = 1944531771    total value = 6642663376
total weight = 1946821635    total value = 6654768552
total weight = 1956576401    total value = 6598594667
total weight = 1973553954    total value = 6252225161
total weight = 1944531771    total value = 6642663376
total weight = 1944531771    total value = 6642663376
total weight = 1946821635    total value = 6654768552
total weight = 1997568486    total value = 6070438783
total weight = 1944531771    total value = 6642663376
total weight = 1956576401    total value = 6598594667
total weight = 1946821635    total value = 6654768552
total weight = 1946821635    total value = 6654768552
total weight = 1944531771    total value = 6642663376
total weight = 1670057539    total value = 6391292585
total weight = 1881346006    total value = 5898972591
total weight = 1944531771    total value = 6642663376
total weight = 1944531771    total value = 6642663376
total weight = 1944531771    total value = 6642663376
total weight = 1988366392    total value = 6264049448
total weight = 1971130380    total value = 4977496842
total weight = 1956576401    total value = 6598594667
total weight = 1884428665    total value = 5906022845
total weight = 1944531771    total value = 6642663376
total weight = 1946745995    total value = 6648157753
total weight = 1946821635    total value = 6654768552
このプログラムを1回実行したときの出力結果
goods0  weight = 137274936  value = 128990795
goods1  weight = 989051853  value = 575374246
goods2  weight = 85168425  value = 471048785
goods3  weight = 856699603  value = 640066776
goods4  weight = 611065509  value = 819841327
goods5  weight = 22345022  value = 704171581
goods6  weight = 678298936  value = 536108301
goods7  weight = 616908153  value = 119980848
goods8  weight = 28801762  value = 117241527
goods9  weight = 478675378  value = 325850062
goods10  weight = 706900574  value = 623319578
goods11  weight = 738510039  value = 998395208
goods12  weight = 135746508  value = 475707585
goods13  weight = 599020879  value = 863910036
goods14  weight = 738084616  value = 340559411
goods15  weight = 545330137  value = 122579234
goods16  weight = 86797589  value = 696368935
goods17  weight = 592749599  value = 665665204
goods18  weight = 401229830  value = 958833732
goods19  weight = 523386474  value = 371084424
goods20  weight = 5310725  value = 463433600
goods21  weight = 907821957  value = 210508742
goods22  weight = 565237085  value = 685281136
goods23  weight = 730556272  value = 619500108
goods24  weight = 310581512  value = 88215377
goods25  weight = 136966252  value = 558193168
goods26  weight = 132739489  value = 475268130
goods27  weight = 12425915  value = 303022740
goods28  weight = 137199296  value = 122379996
goods29  weight = 23505143  value = 304092766

generation0  weight = 6177667707  value = 0  gene = 000001010111001010001111101010
generation1  weight = 6177667707  value = 0  gene = 000001010111001010001111101010
generation2  weight = 1453684641  value = 3664776929  gene = 001001000000010010010000010000
generation3  weight = 1453684641  value = 3664776929  gene = 001001000000010010010000010000
generation4  weight = 1477189784  value = 3968869695  gene = 001001000000010010010000010001
generation5  weight = 1883730339  value = 5391137027  gene = 001001000000010010111000010001
generation6  weight = 1883730339  value = 5391137027  gene = 001001000000010010111000010001
generation7  weight = 1896156254  value = 5694159767  gene = 001001000000010010111000010101
generation8  weight = 1772259433  value = 6204797021  gene = 101001000000100011101000011101
generation9  weight = 1772259433  value = 6204797021  gene = 101001000000100011101000011101
generation10  weight = 1778530713  value = 6403041853  gene = 101001000000110010101000011101
generation11  weight = 1807332475  value = 6520283380  gene = 101001001000110010101000011101
generation12  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation13  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation14  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation15  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation16  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation17  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation18  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation19  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation20  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation21  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation22  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation23  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation24  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation25  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation26  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation27  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation28  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111
generation29  weight = 1944531771  value = 6642663376  gene = 101001001000110010101000011111

number of goods = 30
max weight = 2000000000
total weight = 1944531771
total value = 6642663376
knapsack.cpp
#include <iostream>
#include <algorithm>
#include <time.h>
using namespace std;

int N_G = 30; // 品物の数 (number of goods)
long long MAX_W = 2000000000; // 最大重量 (max weight)
int N_P = 100; // 個体数 (number of population)
int CUT_LINE = 20;
int ITERATION = 30; // 繰り返し回数

long long* weight;
long long* value;

// 個体のクラス
class POPULATION
{
protected:
	int* gene; // 個体の遺伝子
	long long weight_p; // 個体の総重量
	long long value_p; // 個体の総価値
public:
	POPULATION();
	~POPULATION();
	void calc_weight_and_value(); // 個体の総重量と総価値を計算する
	long long get_value() { return value_p; }
	long long get_weight() { return weight_p; }
	void set_gene(int i, int g); // 遺伝子を設定する
	int get_gene(int i) { return gene[i]; }
	void mutation(); // 突然変異
	void initialize(); // 遺伝子の初期化
};

POPULATION** population;

POPULATION::POPULATION()
{
	gene = new int[N_G];
}

POPULATION::~POPULATION()
{
	delete []gene;
}

// 遺伝子の初期化
void POPULATION::initialize()
{
	for (int i = 0; i < N_G; i++)
		set_gene(i, rand() % 2);
	calc_weight_and_value();
}

void POPULATION::set_gene(int i, int g)
{
	gene[i] = g;
	if (weight[i] > MAX_W)
		gene[i] = 0;
}

// 個体の総重量と総価値を計算する
void POPULATION::calc_weight_and_value()
{
	weight_p = 0;
	value_p = 0;
	for (int i = 0; i < N_G; i++) {
		if (gene[i] == 1) {
			weight_p += weight[i];
			value_p += value[i];
		}
	}
	// 総重量が最大重量を超えていた場合は、総価値をゼロに設定
	if (weight_p > MAX_W)
		value_p = 0;
}

// 突然変異
void POPULATION::mutation()
{
	int mutation_point = rand() % N_G;
	if (gene[mutation_point] == 0)
		set_gene(mutation_point, 1);
	else
		set_gene(mutation_point, 0);
}

void create_object()
{
	weight = new long long[N_G]; // 品物の重量を代入するための変数
	value = new long long[N_G]; // 品物の価値を代入するための変数

	// 個体群の生成
	population = new POPULATION*[N_P];
	for (int i = 0; i < N_P; i++)
		population[i] = new POPULATION;
}

// 品物の価値と重量の初期設定
void initialize_weight_and_value()
{
	// N = 30
	value[0] = 128990795; weight[0] = 137274936;
	value[1] = 575374246; weight[1] = 989051853;
	value[2] = 471048785; weight[2] = 85168425;
	value[3] = 640066776; weight[3] = 856699603;
	value[4] = 819841327; weight[4] = 611065509;
	value[5] = 704171581; weight[5] = 22345022;
	value[6] = 536108301; weight[6] = 678298936;
	value[7] = 119980848; weight[7] = 616908153;
	value[8] = 117241527; weight[8] = 28801762;
	value[9] = 325850062; weight[9] = 478675378;
	value[10] = 623319578; weight[10] = 706900574;
	value[11] = 998395208; weight[11] = 738510039;
	value[12] = 475707585; weight[12] = 135746508;
	value[13] = 863910036; weight[13] = 599020879;
	value[14] = 340559411; weight[14] = 738084616;
	value[15] = 122579234; weight[15] = 545330137;
	value[16] = 696368935; weight[16] = 86797589;
	value[17] = 665665204; weight[17] = 592749599;
	value[18] = 958833732; weight[18] = 401229830;
	value[19] = 371084424; weight[19] = 523386474;
	value[20] = 463433600; weight[20] = 5310725;
	value[21] = 210508742; weight[21] = 907821957;
	value[22] = 685281136; weight[22] = 565237085;
	value[23] = 619500108; weight[23] = 730556272;
	value[24] = 88215377; weight[24] = 310581512;
	value[25] = 558193168; weight[25] = 136966252;
	value[26] = 475268130; weight[26] = 132739489;
	value[27] = 303022740; weight[27] = 12425915;
	value[28] = 122379996; weight[28] = 137199296;
	value[29] = 304092766; weight[29] = 23505143;

	for (int i = 0; i < N_G; i++)
		cout << "goods" << i << "  weight = " << weight[i] << "  value = " << value[i] << endl;
	cout << endl;
}

// 個体群の初期設定
void initialize_population()
{
	for (int i = 0; i < N_P; i++) 
		population[i]->initialize();
}


void delete_object()
{
	for (int i = 0; i < N_P; i++)
		delete population[i];
	delete []population;
	delete []value;
	delete []weight;
}

// 個体群を価値が高い順に並べ替える
void ranking()
{
	for (int i = 0; i < N_P - 1; i++) {
		for (int j = i + 1; j < N_P; j++) {
			if (population[i]->get_value() < population[j]->get_value()) {
				POPULATION* tmp = population[i];
				population[i] = population[j];
				population[j] = tmp;
			}
		}
	}
}

// 遺伝子の交叉と突然変異
void cross_over()
{
	for (int i = CUT_LINE; i < N_P; i++) {
		int parent1 = rand() % CUT_LINE; // 1番目の親の遺伝子をカットラインより上位の個体の中から選択
		int parent2 = rand() % CUT_LINE; // 2番目の親の遺伝子をカットラインより上位の個体の中から選択

		int cut_point1 = rand() % N_G; // 1番目の遺伝子の切断ポイントを決定
		int cut_point2 = rand() % N_G; // 2番目の遺伝子の切断ポイントを決定

		// 1番目の交叉ポイントが2番目の交叉ポイントより大きかった場合に入れ替える
		if (cut_point1 > cut_point2) {
			int tmp = cut_point1;
			cut_point1 = cut_point2;
			cut_point2 = tmp;
		}
		
		// 一番目の切断ポイント以下の遺伝子を1番目の親の遺伝子からコピー
		for (int j = 0; j < cut_point1; j++)
			population[i]->set_gene(j, population[parent1]->get_gene(j));
		
		// 1番目の切断ポイントと2番目の切断ポイントの間の遺伝子を2番目の親の遺伝子からコピー
		for (int j = cut_point1; j < cut_point2; j++)
			population[i]->set_gene(j, population[parent2]->get_gene(j));
		
		// 2番目の切断ポイント以降の遺伝子を1番目の親の遺伝子からコピー
		for (int j = cut_point2; j < N_G; j++)
			population[i]->set_gene(j, population[parent1]->get_gene(j));

		// ランダム値が5%より小さかった場合に突然変異を起こす
		if (rand() % 100 < 5)
			population[i]->mutation();

		// 個体の総重量と総価値を計算
		population[i]->calc_weight_and_value();
	}
}

int main()
{
	srand((unsigned)time(NULL));
	create_object(); // 個体群の生成
	initialize_weight_and_value(); // 各品物の重量と価格の初期化

	long long max_value = 0;
	long long final_weight = 0;
	initialize_population(); // 個体群の初期化
	ranking(); // 個体群を価値の高い順番に並び変える
	for (int i = 0; i < ITERATION; i++) {
		cross_over(); // 遺伝子の交叉と突然変異
		ranking(); // 個体群を価値の高い順番に並び変える

		// その世代において最も価値の高かった個体の総重量と総価値の表示
		cout << "generation" << i << "  weight = " << population[0]->get_weight() << "  value = " << population[0]->get_value();
		
		// 価値が最高だった個体の遺伝子の表示
		cout << "  gene = ";
		for (int j = 0; j < N_G; j++)
			cout << population[0]->get_gene(j);
		cout << endl;

		// その世代の価値が最も高かった場合は、総重量と総価値を保存する
		if (max_value < population[0]->get_value()) {
			max_value = population[0]->get_value();
			final_weight = population[0]->get_weight();
		}
	}
	cout << endl;
	cout << "number of goods = " << N_G << "    " << "max weight = " << MAX_W << endl;
	cout << "total weight = " << final_weight << "    total value = " << max_value << endl;

	delete_object();
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?