實(shí)例講解遺傳算法——基于遺傳算法的自動(dòng)組卷系統(tǒng)【實(shí)踐篇】
先上兩張運(yùn)行后的效果圖吧:
基于遺傳算法的自動(dòng)組卷系統(tǒng)運(yùn)行效果圖(1)
基于遺傳算法的自動(dòng)組卷系統(tǒng)運(yùn)行效果圖(2)
一、準(zhǔn)備工作
1、問題實(shí)體
問題實(shí)體包含編號(hào)、類型(類型即題型,分為五種:?jiǎn)芜x,多選,判斷,填空,問答, 分別用1、2、3、4、5表示)、分?jǐn)?shù)、難度系數(shù)、知識(shí)點(diǎn)。一道題至少有一個(gè)知識(shí)點(diǎn),為簡(jiǎn)單易懂,知識(shí)點(diǎn)用List<int> 表示(知識(shí)點(diǎn)編號(hào)集合)。
代碼如下:
public Problem()
{
ID = 0;
Type = 0;
Score = 0;
Difficulty = 0.00;
Points = new List<int>();
}
public Problem(Problem p)
{
this.ID = p.ID;
this.Type = p.Type;
this.Score = p.Score;
this.Difficulty = p.Difficulty;
this.Points = p.Points;
}
/// <summary>
/// 編號(hào)
/// </summary>
public int ID { get; set; }
/// <summary>
/// 題型(1、2、3、4、5對(duì)應(yīng)單選,多選,判斷,填空,問答)
/// </summary>
public int Type { get; set; }
/// <summary>
/// 分?jǐn)?shù)
/// </summary>
public int Score { get; set; }
/// <summary>
/// 難度系數(shù)
/// </summary>
public double Difficulty { get; set; }
/// <summary>
/// 知識(shí)點(diǎn)
/// </summary>
public List<int> Points { get; set; }
}
2、題庫(kù)
為了簡(jiǎn)單,這里沒有用數(shù)據(jù)庫(kù),題目信息臨時(shí)創(chuàng)建,保存在內(nèi)存中。因?yàn)閷?duì)不同層次的考生一道題目在不同試卷中的分?jǐn)?shù)可能不一樣,因此題目分?jǐn)?shù)一般是老師出卷時(shí)定的,不保存在題庫(kù)中。且單選,多選,判斷題每題分?jǐn)?shù)應(yīng)該相同,填空題一般根據(jù)空數(shù)來定分?jǐn)?shù),而問答題一般根據(jù)題目難度來定的,因此這里的單選、多選、判斷分?jǐn)?shù)相同,填空空數(shù)取1-4間的隨機(jī)數(shù),填空題分?jǐn)?shù)即為空數(shù),問答題即為該題難度系數(shù)*10取整。這里各種題型均為1000題,具體應(yīng)用時(shí)改為數(shù)據(jù)庫(kù)即可。
代碼如下:
{
/// <summary>
/// 題庫(kù)
/// </summary>
public List<Problem> ProblemDB;
public DB()
{
ProblemDB = new List<Problem>();
Problem model;
Random rand = new Random();
List<int> Points;
for (int i = 1; i <= 5000; i++)
{
model = new Problem();
model.ID = i;
//試題難度系數(shù)取0.3到1之間的隨機(jī)值
model.Difficulty = rand.Next(30, 100) * 0.01;
//單選題1分
if (i < 1001)
{
model.Type = 1;
model.Score = 1;
}
//單選題2分
if (i > 1000 && i < 2001)
{
model.Type = 2;
model.Score = 2;
}
//判斷題2分
if (i > 2000 && i < 3001)
{
model.Type = 3;
model.Score = 2;
}
//填空題1—4分
if (i > 3000 && i < 4001)
{
model.Type = 4;
model.Score = rand.Next(1, 5);
}
//問答題分?jǐn)?shù)為難度系數(shù)*10
if (i > 4000 && i < 5001)
{
model.Type = 5;
model.Score = model.Difficulty > 0.3 ? (int)(double.Parse(model.Difficulty.ToString("f1")) * 10) : 3;
}
Points = new List<int>();
//每題1到4個(gè)知識(shí)點(diǎn)
int count = rand.Next(1, 5);
for (int j = 0; j < count; j++)
{
Points.Add(rand.Next(1, 100));
}
model.Points = Points;
ProblemDB.Add(model);
}
}
}
3、 試卷實(shí)體
試卷一般包含試卷編號(hào),試卷名稱,考試時(shí)間,難度系數(shù),知識(shí)點(diǎn)分布,總題數(shù), 總分?jǐn)?shù),各種題型所占比率等屬性,這里為簡(jiǎn)單去掉了試卷名稱跟考試時(shí)間。其中的知識(shí)點(diǎn)分布即老師出卷時(shí)選定本試卷要考查的知識(shí)點(diǎn),這里用List<int>(知識(shí)點(diǎn)編號(hào)集合)表示。
代碼如下:
{
/// <summary>
/// 編號(hào)
/// </summary>
public int ID { get; set; }
/// <summary>
/// 總分
/// </summary>
public int TotalScore { get; set; }
/// <summary>
/// 難度系數(shù)
/// </summary>
public double Difficulty { get; set; }
/// <summary>
/// 知識(shí)點(diǎn)
/// </summary>
public List<int> Points { get; set; }
/// <summary>
/// 各種題型題數(shù)
/// </summary>
public int[] EachTypeCount { get; set; }
}
二、開始遺傳算法組卷之旅
準(zhǔn)備工作已經(jīng)OK,下面就按上一篇介紹的流程進(jìn)行操作啦!
1、產(chǎn)生初始種群
這里保證題數(shù)跟總分達(dá)到出卷要求即可,但為操作方便,這里再定義一個(gè)種群個(gè)體實(shí)體類Unit,包含編號(hào)、適應(yīng)度、題數(shù)、總分、難度系數(shù)、知識(shí)點(diǎn)分布、包含的題目等信息(也可以修改一下試卷實(shí)體,用試卷實(shí)體表示):
public class Unit
public Unit()
{
ID = 0;
AdaptationDegree = 0.00;
KPCoverage = 0.00;
ProblemList = new List<Problem>();
}
/// <summary>
/// 編號(hào)
/// </summary>
public int ID { get; set; }
/// <summary>
/// 適應(yīng)度
/// </summary>
public double AdaptationDegree { get; set; }
/// <summary>
/// 難度系數(shù)(本試卷所有題目分?jǐn)?shù)*難度系數(shù)/總分)
/// </summary>
public double Difficulty
{
get
{
double diff = 0.00;
ProblemList.ForEach(delegate(Problem p)
{
diff += p.Difficulty * p.Score;
});
return diff / SumScore;
}
}
/// <summary>
/// 題目數(shù)量
/// </summary>
public int ProblemCount
{
get
{
return ProblemList.Count;
}
}
/// <summary>
/// 總分
/// </summary>
public int SumScore
{
get
{
int sum = 0;
ProblemList.ForEach(delegate(Problem p)
{
sum += p.Score;
});
return sum;
}
}
/// <summary>
/// 知識(shí)點(diǎn)分布
/// </summary>
public double KPCoverage { get; set; }
/// <summary>
/// 題目
/// </summary>
public List<Problem> ProblemList { get; set; }
}
下面即來產(chǎn)生初始種群,按個(gè)體數(shù)量,期望試卷知識(shí)點(diǎn)分布,各類型題目數(shù)等限制產(chǎn)生初始種群:
/// 初始種群
/// </summary>
/// <param name="count">個(gè)體數(shù)量</param>
/// <param name="paper">期望試卷</param>
/// <param name="problemList">題庫(kù)</param>
/// <returns>初始種群</returns>
public List<Unit> CSZQ(int count, Paper paper, List<Problem> problemList)
{
List<Unit> unitList = new List<Unit>();
int[] eachTypeCount = paper.EachTypeCount;
Unit unit;
Random rand = new Random();
for (int i = 0; i < count; i++)
{
unit = new Unit();
unit.ID = i + 1;
unit.AdaptationDegree = 0.00;
//總分限制
while (paper.TotalScore != unit.SumScore)
{
unit.ProblemList.Clear();
//各題型題目數(shù)量限制
for (int j = 0; j < eachTypeCount.Length; j++)
{
List<Problem> oneTypeProblem = problemList
.Where(o => o.Type == (j + 1))
.Where(p => IsContain(paper, p))
.ToList();
Problem temp = new Problem();
for (int k = 0; k < eachTypeCount[j]; k++)
{
//選擇不重復(fù)的題目
int index = rand.Next(0, oneTypeProblem.Count - k);
unit.ProblemList.Add(oneTypeProblem[index]);
temp = oneTypeProblem[oneTypeProblem.Count - 1 - k];
oneTypeProblem[oneTypeProblem.Count - 1 - k] = oneTypeProblem[index];
oneTypeProblem[index] = temp;
}
}
}
unitList.Add(unit);
}
//計(jì)算知識(shí)點(diǎn)覆蓋率及適應(yīng)度
unitList = GetKPCoverage(unitList, paper);
unitList = GetAdaptationDegree(unitList, paper, kpcoverage, difficulty);
return unitList;
}
2、計(jì)算種群個(gè)體的適應(yīng)度
在上面的代碼中最后調(diào)用了兩個(gè)方法,GetKPCoverage跟GetAdaptationDegree,這兩個(gè)方法分別是計(jì)算種群中個(gè)體的知識(shí)點(diǎn)覆蓋率跟適應(yīng)度。
關(guān)于種群個(gè)體的知識(shí)點(diǎn)覆蓋率在上一篇文章中已經(jīng)說過了(知識(shí)點(diǎn)分布用一個(gè)個(gè)體知識(shí)點(diǎn)的覆蓋率來衡量,例如期望本試卷包含N個(gè)知識(shí)點(diǎn),而一個(gè)個(gè)體中所有題目知識(shí)點(diǎn)的并集中包含M個(gè)(M<=N),則知識(shí)點(diǎn)的覆蓋率為M/N。),具體算法如下:
/// <summary>
/// </summary>
/// <param name="unitList">種群</param>
/// <param name="paper">期望試卷</param>
/// <returns>List</returns>
public List<Unit> GetKPCoverage(List<Unit> unitList, Paper paper)
{
List<int> kp;
for (int i = 0; i < unitList.Count; i++)
{
kp = new List<int>();
unitList[i].ProblemList.ForEach(delegate(Problem p)
{
kp.AddRange(p.Points);
});
//個(gè)體所有題目知識(shí)點(diǎn)并集跟期望試卷知識(shí)點(diǎn)交集
var common = kp.Intersect(paper.Points);
unitList[i].KPCoverage = common.Count() * 1.00 / paper.Points.Count;
}
return unitList;
}
適應(yīng)度方法的確定上一篇文章里已經(jīng)說過,即:
f=1-(1-M/N)*f1-|EP-P|*f2
其中M/N為知識(shí)點(diǎn)覆蓋率,EP為期望難度系數(shù),P為種群個(gè)體難度系數(shù),f1為知識(shí)點(diǎn)分布的權(quán)重,f2為難度系數(shù)所占權(quán)重。當(dāng)f1=0時(shí)退化為只限制試題難度系數(shù),當(dāng)f2=0時(shí)退化為只限制知識(shí)點(diǎn)分布。 實(shí)現(xiàn)代碼如下:
/// <summary>
/// </summary>
/// <param name="unitList">種群</param>
/// <param name="paper">期望試卷</param>
/// <param name="KPCoverage">知識(shí)點(diǎn)分布在適應(yīng)度計(jì)算中所占權(quán)重</param>
/// <param name="Difficulty">試卷難度系數(shù)在適應(yīng)度計(jì)算中所占權(quán)重</param>
/// <returns>List</returns>
public List<Unit> GetAdaptationDegree(List<Unit> unitList, Paper paper, double KPCoverage, double Difficulty)
{
unitList = GetKPCoverage(unitList, paper);
for (int i = 0; i < unitList.Count; i++)
{
unitList[i].AdaptationDegree = 1 - (1 - unitList[i].KPCoverage) * KPCoverage - Math.Abs(unitList[i].Difficulty - paper.Difficulty) * Difficulty;
}
return unitList;
}
3、選擇算子
這里選擇算子采用輪盤賭選擇法,即適應(yīng)度越大的被選擇到的概率越大。比如說種群中有20個(gè)個(gè)體,那么每個(gè)個(gè)體的適應(yīng)度除以20個(gè)個(gè)體適應(yīng)度的和得到的就是該個(gè)體的被選擇的概率。輪盤賭選擇時(shí),每個(gè)個(gè)體類似于輪盤中的一小塊扇形,扇形的大小與該個(gè)體被選擇的概率成正比。那么,扇形越大的個(gè)體被選擇的概率越大。這就是輪盤賭選擇法。 算法實(shí)現(xiàn)代碼如下:
/// 選擇算子(輪盤賭選擇)
/// </summary>
/// <param name="unitList">種群</param>
/// <param name="count">選擇次數(shù)</param>
/// <returns>進(jìn)入下一代的種群</returns>
public List<Unit> Select(List<Unit> unitList, int count)
{
List<Unit> selectedUnitList = new List<Unit>();
//種群個(gè)體適應(yīng)度和
double AllAdaptationDegree = 0;
unitList.ForEach(delegate(Unit u)
{
AllAdaptationDegree += u.AdaptationDegree;
});
Random rand = new Random();
while (selectedUnitList.Count != count)
{
//選擇一個(gè)0—1的隨機(jī)數(shù)字
double degree = 0.00;
double randDegree = rand.Next(1, 100) * 0.01 * AllAdaptationDegree;
//選擇符合要求的個(gè)體
for (int j = 0; j < unitList.Count; j++)
{
degree += unitList[j].AdaptationDegree;
if (degree >= randDegree)
{
//不重復(fù)選擇
if (!selectedUnitList.Contains(unitList[j]))
{
selectedUnitList.Add(unitList[j]);
}
break;
}
}
}
return selectedUnitList;
}
4、交叉算子
交叉算子在上一篇也做了說明,寫程序時(shí)為方便略做了一點(diǎn)更改,即把多點(diǎn)交叉改為單點(diǎn)交叉。在交叉過程在有幾個(gè)地方需要注意,一是要保正總分不變,二是保證交叉后沒有重復(fù)個(gè)體,算法實(shí)現(xiàn)如下:
/// <summary>
/// </summary>
/// <param name="unitList">種群</param>
/// <param name="count">交叉后產(chǎn)生的新種群個(gè)體數(shù)量</param>
/// <param name="paper">期望試卷</param>
/// <returns>List</returns>
public List<Unit> Cross(List<Unit> unitList, int count, Paper paper)
{
List<Unit> crossedUnitList = new List<Unit>();
Random rand = new Random();
while (crossedUnitList.Count != count)
{
//隨機(jī)選擇兩個(gè)個(gè)體
int indexOne = rand.Next(0, unitList.Count);
int indexTwo = rand.Next(0, unitList.Count);
Unit unitOne;
Unit unitTwo;
if (indexOne != indexTwo)
{
unitOne = unitList[indexOne];
unitTwo = unitList[indexTwo];
//隨機(jī)選擇一個(gè)交叉位置
int crossPosition = rand.Next(0, unitOne.ProblemCount - 2);
//保證交叉的題目分?jǐn)?shù)合相同
double scoreOne = unitOne.ProblemList[crossPosition].Score + unitOne.ProblemList[crossPosition + 1].Score;
double scoreTwo = unitTwo.ProblemList[crossPosition].Score + unitTwo.ProblemList[crossPosition + 1].Score;
if (scoreOne == scoreTwo)
{
//兩個(gè)新個(gè)體
Unit unitNewOne = new Unit();
unitNewOne.ProblemList.AddRange(unitOne.ProblemList);
Unit unitNewTwo = new Unit();
unitNewTwo.ProblemList.AddRange(unitTwo.ProblemList);
//交換交叉位置后面兩道題
for (int i = crossPosition; i < crossPosition + 2; i++)
{
unitNewOne.ProblemList[i] = new Problem(unitTwo.ProblemList[i]);
unitNewTwo.ProblemList[i] = new Problem(unitOne.ProblemList[i]);
}
//添加到新種群集合中
unitNewOne.ID = crossedUnitList.Count;
unitNewTwo.ID = unitNewOne.ID + 1;
if (crossedUnitList.Count < count)
{
crossedUnitList.Add(unitNewOne);
}
if (crossedUnitList.Count < count)
{
crossedUnitList.Add(unitNewTwo);
}
}
}
//過濾重復(fù)個(gè)體
crossedUnitList = crossedUnitList.Distinct(new ProblemComparer()).ToList();
}
//計(jì)算知識(shí)點(diǎn)覆蓋率及適應(yīng)度
crossedUnitList = GetKPCoverage(crossedUnitList, paper);
crossedUnitList = GetAdaptationDegree(crossedUnitList, paper, kpcoverage, difficulty);
return crossedUnitList;
}
上面過濾重復(fù)個(gè)體中用到了ProblemComparer類,這是一個(gè)自定義的比較類,代碼如下:
public class ProblemComparer : IEqualityComparer<Unit>
public bool Equals(Unit x, Unit y)
{
bool result = true;
for (int i = 0; i < x.ProblemList.Count; i++)
{
if (x.ProblemList[i].ID != y.ProblemList[i].ID)
{
result = false;
break;
}
}
return result;
}
public int GetHashCode(Unit obj)
{
return obj.ToString().GetHashCode();
}
}
5、 變異算子
在變異過程中主要是要保證替換題目至少包含一個(gè)被替換題的有效知識(shí)點(diǎn)(期望試卷中也包含此知識(shí)點(diǎn)),并要類型相同,分?jǐn)?shù)相同而題號(hào)不同。 算法實(shí)現(xiàn)代碼如下:
/// 變異算子
/// </summary>
/// <param name="unitList">種群</param>
/// <param name="problemList">題庫(kù)</param>
/// <param name="paper">期望試卷</param>
/// <returns>List</returns>
public List<Unit> Change(List<Unit> unitList, List<Problem> problemList, Paper paper)
{
Random rand = new Random();
int index = 0;
unitList.ForEach(delegate(Unit u)
{
//隨機(jī)選擇一道題
index = rand.Next(0, u.ProblemList.Count);
Problem temp = u.ProblemList[index];
//得到這道題的知識(shí)點(diǎn)
Problem problem = new Problem();
for (int i = 0; i < temp.Points.Count; i++)
{
if (paper.Points.Contains(temp.Points[i]))
{
problem.Points.Add(temp.Points[i]);
}
}
//從數(shù)據(jù)庫(kù)中選擇包含此題有效知識(shí)點(diǎn)的同類型同分?jǐn)?shù)不同題號(hào)試題
var otherDB = from a in problemList
where a.Points.Intersect(problem.Points).Count() > 0
select a;
List<Problem> smallDB = otherDB.Where(p => IsContain(paper, p)).Where(o => o.Score == temp.Score && o.Type == temp.Type && o.ID != temp.ID).ToList();
//從符合要求的試題中隨機(jī)選一題替換
if (smallDB.Count > 0)
{
int changeIndex = rand.Next(0, smallDB.Count);
u.ProblemList[index] = smallDB[changeIndex];
}
});
//計(jì)算知識(shí)點(diǎn)覆蓋率跟適應(yīng)度
unitList = GetKPCoverage(unitList, paper);
unitList = GetAdaptationDegree(unitList, paper, kpcoverage, difficulty);
return unitList;
}
6、調(diào)用示例
遺傳算法主要算法上面都已實(shí)現(xiàn),現(xiàn)在就是調(diào)用了。調(diào)用過程按如下流程圖進(jìn)行:
基于遺傳算法的自動(dòng)組卷系統(tǒng)流程圖
這里初始種群大小設(shè)定為20,最大迭代次數(shù)為500,適應(yīng)度為0.98,選擇算子選擇次數(shù)為10次,交叉算子產(chǎn)生的個(gè)體數(shù)量為20,期望試卷難度系數(shù)為0.72,總分為100分,各種題型題數(shù)為:20(單選), 5(多選), 10(判斷), 7(填空), 5(問答),包含的知識(shí)點(diǎn)為:1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81。代碼如下:
/// 調(diào)用示例
/// </summary>
public void Show()
{
//題庫(kù)
DB db = new DB();
//期望試卷
Paper paper = new Paper()
{
ID = 1,
TotalScore = 100,
Difficulty = 0.72,
Points = new List<int>() { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81 },
EachTypeCount = new[] { 20, 5, 10, 7, 5 }
};
//迭代次數(shù)計(jì)數(shù)器
int count = 1;
//適應(yīng)度期望值
double expand = 0.98;
//最大迭代次數(shù)
int runCount = 500;
//初始化種群
List<Unit> unitList = CSZQ(20, paper, db.ProblemDB);
Console.WriteLine("\n\n -------遺傳算法組卷系統(tǒng)(http://www.rzrgm.cn/durongjian/)---------\n\n");
Console.WriteLine("初始種群:");
ShowUnit(unitList);
Console.WriteLine("-----------------------迭代開始------------------------");
//開始迭代
while (!IsEnd(unitList, expand))
{
Console.WriteLine("在第 " + (count++) + " 代未得到結(jié)果");
if (count > runCount)
{
Console.WriteLine("計(jì)算 " + runCount + " 代仍沒有結(jié)果,請(qǐng)重新設(shè)計(jì)條件!");
break;
}
//選擇
unitList = Select(unitList, 10);
//交叉
unitList = Cross(unitList, 20, paper);
//是否可以結(jié)束(有符合要求試卷即可結(jié)束)
if (IsEnd(unitList, expand))
{
break;
}
//變異
unitList = Change(unitList, db.ProblemDB, paper);
}
if (count <= runCount)
{
Console.WriteLine("在第 " + count + " 代得到結(jié)果,結(jié)果為:\n");
Console.WriteLine("期望試卷難度:" + paper.Difficulty + "\n");
ShowResult(unitList, expand);
}
}
最后在控制臺(tái)中調(diào)用此方法即可。
7、其他輔助方法
在上面的代碼中還調(diào)用了幾個(gè)輔助方法,下面一并給出:
/// <summary>
/// 是否達(dá)到目標(biāo)
/// </summary>
/// <param name="unitList">種群</param>
/// <param name="endcondition">結(jié)束條件(適應(yīng)度要求)</param>
/// <returns>bool</returns>
public bool IsEnd(List<Unit> unitList, double endcondition)
{
if (unitList.Count > 0)
{
for (int i = 0; i < unitList.Count; i++)
{
if (unitList[i].AdaptationDegree >= endcondition)
{
return true;
}
}
}
return false;
}
#endregion
#region 顯示結(jié)果
/// <summary>
/// 顯示結(jié)果
/// </summary>
/// <param name="unitList">種群</param>
/// <param name="expand">期望適應(yīng)度</param>
public void ShowResult(List<Unit> unitList, double expand)
{
unitList.OrderBy(o => o.ID).ToList().ForEach(delegate(Unit u)
{
if (u.AdaptationDegree >= expand)
{
Console.WriteLine("第" + u.ID + "套:");
Console.WriteLine("題目數(shù)量\t知識(shí)點(diǎn)分布\t難度系數(shù)\t適應(yīng)度");
Console.WriteLine(u.ProblemCount + "\t\t" + u.KPCoverage.ToString("f2") + "\t\t" + u.Difficulty.ToString("f2") + "\t\t" + u.AdaptationDegree.ToString("f2")+"\n\n");
}
});
}
#endregion
#region 顯示種群個(gè)體題目編號(hào)
/// <summary>
/// 顯示種群個(gè)體題目編號(hào)
/// </summary>
/// <param name="u">種群個(gè)體</param>
public void ShowUnit(Unit u)
{
Console.WriteLine("編號(hào)\t知識(shí)點(diǎn)分布\t難度系數(shù)");
Console.WriteLine(u.ID + "\t" + u.KPCoverage.ToString("f2") + "\t\t" + u.Difficulty.ToString("f2"));
u.ProblemList.ForEach(delegate(Problem p)
{
Console.Write(p.ID + "\t");
});
Console.WriteLine();
}
#endregion
經(jīng)園友提醒,少了一個(gè)方法,這里補(bǔ)上:
/// <summary>
/// 題目知識(shí)點(diǎn)是否符合試卷要求
/// </summary>
/// <param name="paper">期望試卷</param>
/// <param name="problem">一首試題</param>
/// <returns>bool</returns>
private bool IsContain(Paper paper, Problem problem)
{
for (int i = 0; i < problem.Points.Count; i++)
{
if (paper.Points.Contains(problem.Points[i]))
{
return true;
}
}
return false;
}
#endregion
后記
大功告成啦,運(yùn)行效果在文章開頭已經(jīng)給出。 當(dāng)然,由于題庫(kù)每次運(yùn)行都不同,因此每次運(yùn)行的結(jié)果也都不同。文中適應(yīng)度函數(shù)用的是線性的,也可以根據(jù)運(yùn)行情況進(jìn)行適當(dāng)調(diào)整,優(yōu)化,歡迎大家提出不同意見。

作者:Artwl
本文首發(fā)博客園,版權(quán)歸作者跟博客園共有。轉(zhuǎn)載必須保留本段聲明,并在頁(yè)面顯著位置給出本文鏈接,否則保留追究法律責(zé)任的權(quán)利。
浙公網(wǎng)安備 33010602011771號(hào)