遺傳算法解決01揹包

參考自: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();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章