參考自:https://blog.csdn.net/liyuming0000/article/details/48394587
我只是修改了一下,代碼可以直接跑。
import java.util.*;
public class test3 {
private Random random = null; //隨機數生成器
private int[] weight ; //物品重量
private int[] profit ; //物品價值
private int len; // 染色體長度
private float capacity; //揹包容量
private int scale; //種羣規模
private int maxgen; //最大代數
private float irate; //交叉率(所有的個體都需要相互交叉的,這裏的交叉率指交叉時每位交叉發生交叉的可能性)
private float arate1; //變異率(某個個體發生變異的可能性)
private float arate2; //對於確定發生變異的個體每位發生變異的可能性
private boolean[][] population = null; //上一代種羣
private float[] fitness = null; //種羣的適應度
private float bestFitness; //最優個體的價值
private boolean[] bestUnit = null; //最優個體的物品取捨策略
class SortFitness implements Comparable<SortFitness>{
int index;
float fitness;
public int compareTo(SortFitness c) {
float cfitness = c.fitness;
if(fitness > cfitness) {
return -1;
} else if(fitness < cfitness) {
return 1;
} else {
return 0;
}
}
}
//種羣規模
//最大代數
//交叉率(所有的個體都需要相互交叉的,這裏的交叉率指交叉時每位交叉發生交叉的可能性)
//變異率(某個個體發生變異的可能性)
//對於確定發生變異的個體每位發生變異的可能性
public test3( int scale, int maxgen, float irate, float arate1, float arate2) {
this.scale = scale;
this.maxgen = maxgen;
this.irate = irate;
this.arate1 = arate1;
this.arate2 = arate2;
random = new Random(System.currentTimeMillis());
}
private void readDate() {
Scanner scanner = new Scanner(System.in);
System.out.println("輸入物品個數");
len=scanner.nextInt();
System.out.println("輸入揹包容量");
capacity=scanner.nextInt();
weight=new int[len];
profit=new int[len];
System.out.println("輸入物品重量和價值");
for (int i = 0; i < len; i++) {
weight[i]=scanner.nextInt();
profit[i]=scanner.nextInt();
}
}
//初始化初始種羣
private void initPopulation() {
fitness = new float[scale];
population = new boolean[scale][len];
//考慮到隨機生成的初始化種羣效果有可能不好,這裏對於種羣的初始化作了一定的優化
//對於每一個個體,先隨機一個容量值(0.5 capacity 至 1.5 capacity)
//然後隨機相應的物品到該個體中,直到超過上面隨機的容量
for(int i = 0; i < scale; i++) {
float tmp = (float)(0.5 + Math.random()) * capacity;
int count = 0; //防止初始化耗費太多計算資源
for(int j = 0; j < tmp;) {
int k = random.nextInt(len);
if(population[i][k]) {
if(count == 3) {
break;
}
count++;
continue;
} else {
population[i][k] = true;
j += weight[k];
count = 0;
}
}
}
}
//計算一個個體的適應度
private float evaluate(boolean[] unit) {
float profitSum = 0;
float weightSum = 0;
for (int i = 0; i < unit.length; i++) {
if (unit[i]) {
weightSum += weight[i];
profitSum += profit[i];
}
}
if (weightSum > capacity) {
//該個體的對應的所有物品的重量超過了揹包的容量
return 0;
} else {
return profitSum;
}
}
//計算種羣所有個體的適應度
private void calcFitness() {
for(int i = 0; i < scale; i++) {
fitness[i] = evaluate(population[i]);
}
}
//記錄最優個體
private void recBest(int gen) {
for(int i = 0; i < scale; i++) {
if(fitness[i] > bestFitness) {
bestFitness = fitness[i];
bestUnit = new boolean[len];
for(int j = 0; j < len; j++) {
bestUnit[j] = population[i][j];
}
}
}
}
//種羣個體選擇
//選擇策略:適應度前10%的個體帶到下一次循環中,然後在(隨機生成10%的個體 + 剩下的90%個體)中隨機取90%出來
private void select() {
SortFitness[] sortFitness = new SortFitness[scale];
for(int i = 0; i < scale; i++) {
sortFitness[i] = new SortFitness();
sortFitness[i].index = i;
sortFitness[i].fitness = fitness[i];
}
Arrays.sort(sortFitness);
boolean[][] tmpPopulation = new boolean[scale][len];
//保留前10%的個體
int reserve = (int)(scale * 0.1);
for(int i = 0; i < reserve; i++) {
for(int j = 0; j < len; j++) {
tmpPopulation[i][j] = population[sortFitness[i].index][j];
}
//將加入後的個體隨機化
for(int j = 0; j < len; j++) {
population[sortFitness[i].index][j] = false;
}
float tmpc = (float)(0.5 + Math.random()) * capacity;
int count = 0;
for(int j = 0; j < tmpc;) {
int k = random.nextInt(len);
if(population[sortFitness[i].index][k]) {
if(count == 3) {
break;
}
count++;
continue;
} else {
population[sortFitness[i].index][k] = true;
j += weight[k];
count = 0;
}
}//
}
//再隨機90%的個體出來
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < scale; i++) {
list.add(i);
}
for(int i = reserve; i < scale; i++) {
int selectid = list.remove((int)(list.size()*Math.random()));
for(int j = 0; j < len; j++) {
tmpPopulation[i][j] = population[selectid][j];
}
}
population = tmpPopulation;
}
//進行交叉
private void intersect() {
for(int i = 0; i < scale; i = i + 2)
for(int j = 0; j < len; j++) {
if(Math.random() < irate) {
boolean tmp = population[i][j];
population[i][j] = population[i + 1][j];
population[i + 1][j] = tmp;
}
}
}
//變異
private void aberra() {
for(int i = 0; i < scale; i++) {
if(Math.random() > arate1) {
continue;
}
for(int j = 0; j < len; j++) {
if(Math.random() < arate2) {
population[i][j] = Math.random() > 0.5 ? true : false;
}
}
}
}
//遺傳算法
public void solve() {
readDate();
initPopulation();
for(int i = 0; i < maxgen; i++) {
//計算種羣適應度值
calcFitness();
//記錄最優個體
recBest(i);
//進行種羣選擇
select();
//進行交叉
intersect();
//發生變異
aberra();
}
int totalWeight = 0;
for(int i = 0; i < bestUnit.length; i++) {
if(bestUnit[i]){
totalWeight += weight[i];
}
}
System.out.println( bestFitness);
}
public static void main(String[] args) {
//種羣規模
//最大代數
//交叉率(所有的個體都需要相互交叉的,這裏的交叉率指交叉時每位交叉發生交叉的可能性)
//變異率(某個個體發生變異的可能性)
//對於確定發生變異的個體每位發生變異的可能性
test3 gaKnapsack = new test3(2000, 2000, 0.5f, 0.05f, 0.1f);
gaKnapsack.solve();
}
}