1. 程式人生 > >CSharp遺傳算法求解背包問題

CSharp遺傳算法求解背包問題

amp pri -1 str orderby count sin console foreach

斷斷續續寫了四天,感覺背包問題是最適合了解遺傳算法的問題模型

技術分享

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bag
{


    /// <summary>
    /// 背包類
    /// </summary>
    public class Bag
    {
        public int Size { get; }
        public Bag(int Size)
        {
            this.Size = Size;
        }
    }
    /// <summary>
    /// 貨物類
    /// </summary>
    public class Goods
    {
        public int Weight { set; get; }
        public int Value { set; get; }
        /// <summary>
        /// 這裏隨機生成貨物屬性
        /// </summary>
        public Goods()
        {
            this.Weight = APP.Rd.Next() % 200 + 10;
            this.Value = APP.Rd.Next() % 1000 + 50;
        }
    }
    /// <summary>
    /// 測試結果,編號,總重與總價
    /// </summary>
    public class Total
    {
        public int Index { set; get; }
        public long TotalWeight { set; get; }
        public long TotalValue { get; set; }
        public Total(int Index, long TotalWeight, long TotalValue)
        {
            this.Index = Index;
            this.TotalWeight = TotalWeight;
            this.TotalValue = TotalValue;
        }
    }




    public class Chromosome
    {
        private bool[] _GeneList = new bool[APP.GoodsNumber];
        public bool[] GeneList
        {
            get
            {
                return this._GeneList;
            }
        }
        public Chromosome()
        {
            for (int i = 0; i < APP.GoodsNumber; ++i)
            {
                this._GeneList[i] = ((APP.Rd.Next() % 2) == 0);
            }
        }
        public Chromosome(Chromosome Father, Chromosome Mother)
        {
            int CutPoint = (APP.Rd.Next() % (APP.GoodsNumber - 1)) + 1;
            Array.Copy(Father._GeneList, 0, this._GeneList, 0, CutPoint);
            Array.Copy(Mother._GeneList, CutPoint, this._GeneList, CutPoint, APP.GoodsNumber - CutPoint);
            if ((APP.Rd.Next() % APP.Mutation) == 0)
            {
                var MutationIndexList = APP.RandomSelect(APP.MutationNumber);
                foreach (var Index in MutationIndexList)
                {
                    this._GeneList[Index] = !this._GeneList[Index];
                }
            }
        }
    }




    public class Population
    {
        private Chromosome[] _ChromosomeList = new Chromosome[APP.PopulationSize];
        public Chromosome[] ChromosomeList
        {
            get
            {
                return this._ChromosomeList;
            }
        }

        private Total Test(int Index, Chromosome pChromosome, Goods[] pGoodsList)
        {
            long WeightSum = 0;
            long ValueSum = 0;
            int i = 0;
            foreach (var BValue in pChromosome.GeneList)
            {
                if (BValue)
                {
                    WeightSum += pGoodsList[i].Weight;
                    ValueSum += pGoodsList[i].Value;
                }
                ++i;
            }
            return new Total(Index, WeightSum, ValueSum);
        }



        public Population()
        {
            for (int i = 0; i < APP.PopulationSize; ++i)
            {
                this._ChromosomeList[i] = new Chromosome();
            }
        }


        /// <summary>
        /// 隨機選取一個繁殖對象
        /// </summary>
        /// <returns></returns>
        public int Select()
        {
            for (int i = 0; i < APP.PopulationSize; ++i)
            {
                if (APP.Rd.Next() % 2 == 0)
                {
                    return i;
                }
            }
            return APP.PopulationSize - 1;
        }
        /// <summary>
        /// 隨機選取兩個不同的繁殖對象
        /// </summary>
        /// <param name="Index1"></param>
        /// <param name="Index2"></param>
        public void SelectDouble(out int Index1, out int Index2)
        {
            int I1 = -1, I2 = -1;
            while (I1 == I2)
            {
                I1 = Select();
                I2 = Select();
            }
            Index1 = I1;
            Index2 = I2;
        }

        /// <summary>
        /// 總群演化方法
        /// </summary>
        /// <param name="pBag">背包</param>
        /// <param name="pGoodsList">商品清單</param>
        /// <returns></returns>
        public Total[] Evolution(Bag pBag, Goods[] pGoodsList)
        {
            Total[] TotalList = new Total[this.ChromosomeList.Count()];
            for (int i = 0; i < this.ChromosomeList.Count(); ++i)
            {
                TotalList[i] = Test(i, this.ChromosomeList[i], pGoodsList);
            }
            var OkList = TotalList.Where(p => p.TotalWeight <= pBag.Size).OrderByDescending(p => p.TotalValue);
            var OutList = TotalList.Where(p => p.TotalWeight > pBag.Size).OrderByDescending(p =>
            {
                double BaseA = (double)p.TotalValue / p.TotalWeight;
                double BaseB = ((double)pBag.Size * pBag.Size) / ((double)p.TotalWeight * p.TotalWeight);
                return BaseA * BaseB;
            });

            var NewList = OkList.Concat(OutList).ToArray();
            var SubChromosomeList = new Chromosome[APP.PopulationSize];

            int FatherIndex;
            int MotherIndex;
            SelectDouble(out FatherIndex, out MotherIndex);
            var Father = this.ChromosomeList[NewList[FatherIndex].Index];
            var Mother = this.ChromosomeList[NewList[MotherIndex].Index];

            for (int i = 0; i < SubChromosomeList.Count(); ++i)
            {
                if (i % 2 == 0)
                {
                    SubChromosomeList[i] = new Chromosome(Father, Mother);
                }
                else
                {
                    SubChromosomeList[i] = new Chromosome(Mother, Father);
                    SelectDouble(out FatherIndex, out MotherIndex);
                    Father = this.ChromosomeList[TotalList[FatherIndex].Index];
                    Mother = this.ChromosomeList[TotalList[MotherIndex].Index];
                }
            }

            this._ChromosomeList = SubChromosomeList;

            return NewList;
        }
    }


    public class APP
    {
        //偽隨機數產生器
        public static Random Rd = new Random();
        //貨物個數,對應染色體基因長度
        public static int GoodsNumber = 200;
        //突變比率倒數
        public static int Mutation = 10;
        //突變基因數量
        public static int MutationNumber = 2;
        //種群大小
        public static int PopulationSize = 1000;

        /// <summary>
        /// 從列表之中隨機選取一定數量的元素
        /// </summary>
        /// <typeparam name="T">類型</typeparam>
        /// <param name="pList">源列表</param>
        /// <param name="pLen">隨機選取的元素列表長度</param>
        /// <returns></returns>
        public static List<T> GetRandomList<T>(IEnumerable<T> pList, int pLen)
        {
            if (pLen > pList.Count())
            {
                pLen = pList.Count();
            }
            List<T> TmpList = pList.ToList<T>();
            List<T> DstList = new List<T>();
            for (int i = 0; i < pLen && TmpList.Count() > 1; ++i)
            {
                int Index = APP.Rd.Next() % TmpList.Count();
                DstList.Add(TmpList[Index]);
                TmpList.RemoveAt(Index);
            }
            return DstList;
        }
        /// <summary>
        /// 隨機選取一定數量的Index序列
        /// </summary>
        /// <param name="Num">數量</param>
        /// <returns></returns>
        public static List<int> RandomSelect(int Num)
        {
            int[] NumList = new int[APP.GoodsNumber];
            for (int i = 0; i < APP.GoodsNumber; ++i)
            {
                NumList[i] = i;
            }
            return GetRandomList<int>(NumList, Num);
        }

        public APP()
        {
            #region 初始化背包與貨物列表
            Bag MyBag = new Bag(10000);
            Goods[] GoodsList = new Goods[APP.GoodsNumber];
            for (int i = 0; i < GoodsList.Count(); ++i)
            {
                GoodsList[i] = new Goods();
            }
            #endregion

            #region 創建總群與進行演化
            Population iPopulation = new Population();
            Total MaxTotal = null;
            while (true)
            {
                var Fst = iPopulation.Evolution(MyBag, GoodsList).First();
                if (MaxTotal == null)
                {
                    MaxTotal = Fst;
                }
                else
                {
                    if (Fst.TotalValue > MaxTotal.TotalValue)
                    {
                        MaxTotal = Fst;
                    }
                }
                //這裏沒有保存染色體,僅僅是取出當前總群的最優結果顯示
                Console.WriteLine("Value: " + MaxTotal.TotalValue + "  Weight: " + MaxTotal.TotalWeight);
            }
            #endregion
        }
    }



    public class Program
    {
        static void Main(string[] args)
        {
            APP App = new APP();
        }
    }
}

  

CSharp遺傳算法求解背包問題