遗传算法实现自动组卷、随机抽题

 公司客户最近要做一个在线考试系统,其中难点在于自动组卷,因为普通的随机方法难度不好掌握,所以领导希望采用遗传算法。算法研究的任务领导交给了我,希望能在端午放假回来看到结果。而我之前并没有听说过遗传算法(孤陋寡闻),但领导分配的任务我不可能说不做(不做回家种地去),所以硬着头皮接了下来,开始GOOGLE遗传算法原理。其中一篇博文基于遗传算法自动组卷的实现对我帮助很大,同时我也联系了此博文的作者,希望能得到他的指点。没想到下午就收到回信,说这篇文章只是纯理论的研究。真正的项目早已找不到了。另外信中给了我几篇关于遗传算法的资料,给了我最直接的帮助。废话不多说,下面直接给代码,代码不难,我也不做解释,请有兴趣的童鞋自己研究(代码现在只是在测试阶段,写得很乱,将就着看吧):

 

using System;
using System.Windows.Forms;
using System.IO;

namespace GA
{
    public partial class Form1 : Form
    {
        TTm[] TP;
        int _ts = 0;
        int n = 10;
        int m = 12;
        int Pc = 50;  //杂交的概率
        int Pm = 80;  //变异的概率
        decimal _nd = 2;
        int[] Fs = { 2, 2, 2, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 15, 20, 20, 20, 20 };  //题目分数
        int[] Nd = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5 };  //题目难度
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            n = Fs.Length;
            m = Fs.Length;
            TP = new TTm[n];
            var P = TP;
            int E, t;
            for (int i = 0; i < n; i++)
            {
                P[i].T = new KT[m];
            }
            Initialize(P);
            if (!textBox4.Text.Equals(""))
                _nd = decimal.Parse(textBox4.Text);
            t = 0;
            E = Evaluate(P);
            decimal _result = 0;
            while (P[E].f < 100 || _ts < 12 || Math.Round((decimal)P[E].nd / _ts, 2) < _nd)  //分数小于100或者题数小于12或者难度小于2继续循环
            {
                Crossover(P);//杂交 
                Mutation(P);//变异
                E = Evaluate(P);//评估种群
                t = t + 1;
                textBox1.Text = t.ToString();
                textBox2.Text = P[E].f.ToString();
                Print(P[E]);//输出
                if (_ts != 0)
                {
                    _result = Math.Round((decimal)P[E].nd / _ts, 2);
                    textBox4.Text = _result.ToString();//(P[E].nd /_ts)
                }
                Application.DoEvents();//使程序响应事件,避免假死无法退出现象
                if (P[E].f == 100 && _ts >= 12 && _result >= _nd)  //总分等于100并且题数大于等于12并且难度系数大于等于2停止循环
                {
                    _ts = 0;
                    break;
                }
                Select(P);//择优
            }
        }

        /// <summary>
        /// 初始化种群
        /// </summary>
        /// <param name="P"></param>
        private void Initialize(TTm[] P)
        {
            int i, j, G;
            for (i = 0; i < n; i++)
            {
                for (j = 0; j < m; j++)
                {
                    P[i].T[j].Fs = Fs[j];
                    P[i].T[j].nd = Nd[j];
                    P[i].T[j].Se = 0;
                }
            }
            Random rnd = new Random();
            int temp = rnd.Next(m);
            for (i = 0; i < n; i++)
            {
                G = 0;
                while (Math.Abs(G - 105) > 10 && G < 130)
                {
                    if (P[i].T[temp].Se == 0)
                    {
                        P[i].T[temp].Se = 1;
                        G = G + P[i].T[temp].Fs;
                        P[i].T[temp].Se = 0;
                    }
                }
            }

        }

        /// <summary>
        /// 评估种群
        /// </summary>
        /// <param name="P"></param>
        private int Evaluate(TTm[] P)
        {
            int i, j, G, D = 0, result = 0;
            for (i = 0; i < n; i++)
            {
                G = 0;
                for (j = 0; j < m; j++)
                {
                    if (P[i].T[j].Se == 1)
                    {
                        G = G + P[i].T[j].Fs;
                        D = D + P[i].T[j].nd;
                    }
                }
                P[i].f = 100 - Math.Abs(G - 100);
                P[i].nd = D;
                if (P[i].f > P[result].f && P[i].nd > P[result].nd)
                    result = i;
            }
            return result;
        }

        /// <summary>
        /// 杂交
        /// </summary>
        /// <param name="P"></param>
        private void Crossover(TTm[] P)
        {
            int i = 0, j = 1, k, t;
            Random rnd = new Random();
            while (i < n - 1)
            {
                if (rnd.Next(101) > Pc)
                {
                    //for (k = rnd.Next(m); k < m; k++)//一点杂交
                    for (k = rnd.Next(m); k <= rnd.Next(m); k++)//两点杂交
                    {
                        t = P[i].T[k].Se;
                        P[i].T[k].Se = P[j].T[k].Se;
                        P[j].T[k].Se = t;
                    }
                }
                i += 2; j += 1;
            }
        }

        /// <summary>
        /// 变异
        /// </summary>
        /// <param name="P"></param>
        private void Mutation(TTm[] P)
        {
            int i;
            Random rnd = new Random();
            for (i = 0; i < n; i++)
            {
                if (rnd.Next(101) > Pm)
                {
                    P[i].T[rnd.Next(m)].Se = Convert.ToInt32(!Convert.ToBoolean(P[i].T[rnd.Next(m)].Se));
                }
            }
        }

        /// <summary>
        /// 择优
        /// </summary>
        /// <param name="P"></param>
        private void Select(TTm[] P)
        {
            int i, j;
            TTm Tm;
            for (i = 0; i < n - 1; i++)   //对种群按优劣排序
            {
                for (j = i + 1; j < n; j++)
                {
                    if (P[i].f > P[j].f)
                    {
                        Tm = P[i];
                        P[i] = P[j];
                        P[j] = Tm;
                    }
                }
            }
            for (i = 0; i <= (n - 1) / 2; i++)   //淘汰50%劣等品种
            {
                P[n - 1 - i] = P[i];
            }
        }

        /// <summary>
        /// 输出
        /// </summary>
        /// <param name="Tm"></param>
        private void Print(TTm Tm)
        {
            string s1, s2;
            int i;
            _ts = 0;
            s1 = "题号:";
            s2 = "分值:";
            for (i = 0; i < m; i++)
            {
                if (Tm.T[i].Se == 1)
                {
                    s1 = s1 + (i+1) + " ";
                    s2 = s2 + Tm.T[i].Fs + " ";
                    _ts++;
                }
            }
            textBox3.Text = s1 + "\r\n" + s2 + "\r\n题数:" + _ts;
        }
    }

    public struct KT
    {
        public int Fs;
        public int nd;
        public int Se;
    }

    public struct TTm
    {
        public KT[] T;
        public int f;
        public int nd;
    }
}

 

下面的图是运行结果:

 《遗传算法实现自动组卷、随机抽题》

 

转自:http://www.cnblogs.com/JasonChou/archive/2010/06/10/1755566.html

    原文作者:遗传算法
    原文地址: https://www.cnblogs.com/chenweichu/articles/5666450.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞