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

         公司客户最近要做一个在线考试系统,其中难点在于自动组卷,因为普通的随机方法难度不好掌握,所以领导希望采用遗传算法。算法研究的任务领导交给了我,希望能在端午放假回来看到结果。而我之前并没有听说过遗传算法(孤陋寡闻),但领导分配的任务我不可能说不做(不做回家种地去),所以硬着头皮接了下来,开始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 = { 2223335555555510101010151515151520202020 };  //题目分数
        int[] Nd = { 111111222222223333444445555 };  //题目难度
        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;
    }
}

 

下面的图是运行结果:

 

posted @ 2010-06-10 13:37  JasonChou  阅读(5403)  评论(15编辑  收藏  举报