最近是准备研究基于自适应遗传算法的排课系统,在研究这个话题之前,我对传统的遗传算法做了相应的调研,其中Python和Java都有实现的案例可以参考,没有找到合适的C#参考代码,So自己动手丰衣足食了。
借助:(225条消息) 基于遗传算法的排课算法思路_萨埵十二的博客-CSDN博客的思路,用C#完成代码编写,下面是关键代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Education.Models
{
public class Schedule
{
public int etaskid;//任务id
public string roomid;//教室id
public string tid;//上课时间id
public int weekday; //周几上课(1-7)
public int slot; //第几节课(12 34 56 78 910 11)==》(1-6)
public Schedule()
{
}
public Schedule(int etaskid)
{
this.etaskid = etaskid;
}
public void random_init(List<string> rooms,int i)
{
Random random = new Random(int.Parse(DateTime.Now.ToString("HHmmssfff"))+i);//利用提高随机种子进行随机生成
this.roomid = rooms.ElementAt(random.Next(rooms.Count() - 1));
// this.tid = times.ElementAt(random.Next(times.Count() - 1)).EID;
this.weekday = (int)(1 + random.Next(0,10) * (5 - 1 + 1));
this.slot = (int)(1 + random.Next(0, 10) * (4 - 1 + 1));
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Education.Models
{
public class MyGa
{
private int popsize = 32;//种群规模
private double mutprob = 0.3;//种群的变异概率
private int elite = 15;//精英个数
private int maxiter = 500;//进化代数(100-500)
private List<List<Schedule>> population;
public List<Schedule> Education(List<Schedule> schedules,List<string> roomRang)
{
int bestScore = 0;
List<Schedule> bestschedule = new List<Schedule>();
// 初始化种群
init_population(schedules, roomRang);
for (int i = 0; i < this.maxiter; i++)
{
List<List<Schedule>> newPopulation = new List<List<Schedule>>();
//获取冲突结果
Dictionary<List<Schedule>,int> cost_map = schedule_cost(this.population, this.elite);
foreach (List<Schedule> key in cost_map.Keys)
{
//若发现冲突结果为0,则说明咳将其当做最优排课结果返回
bestScore = cost_map[key];
if(bestScore==0)
{
bestschedule = key;
return bestschedule;
}
}
//精英种群
newPopulation = cost_map.Keys.ToList();
while (newPopulation.Count < this.popsize)
{
List<Schedule> temp = new List<Schedule>();
if((new Random().Next(0, 10) / 10.0) < this.mutprob)
{
//落在变异概率内,变异
temp = Mutate(newPopulation, roomRang);
}
else
{
//交叉
temp = Crossover(newPopulation);
}
newPopulation.Add(temp);
}
this.population = newPopulation;
}
return bestschedule;
}
/// <summary>
/// 变异 根据精英种群集合 在将其中随机一个染色体变异后 返回变异后的染色体
/// </summary>
/// <param name="elitePopulation"></param>
/// <param name="roomRange"></param>
/// <returns></returns>
List<Schedule> Mutate(List<List<Schedule>> elitePopulation,List<string> roomRange)
{
Random random = new Random();
int getIndex = random.Next(elitePopulation.Count);
List<Schedule> ep = elitePopulation[getIndex];
foreach (Schedule s in ep)
{
int pos = random.Next(3);
if (pos == 0)
{
s.roomid = roomRange[random.Next(roomRange.Count)];
}else if (pos == 1)
{
s.weekday=((int)(1 + random.Next(0, 10) * (5 - 1 + 1)));
}else if (pos == 2)
{
s.slot = (int)(1 + random.Next(0, 10) * (4 - 1 + 1));
}
}
return ep;
}
/// <summary>
/// 交叉
/// </summary>
/// <param name="elitePopulation"></param>
/// <returns></returns>
List<Schedule> Crossover(List<List<Schedule>> elitePopulation)
{
Random random = new Random();
int getIndex1 = random.Next(elitePopulation.Count);
int getIndex2 = random.Next(elitePopulation.Count);
List<Schedule> e1 = elitePopulation[getIndex1];
List<Schedule> e2 = elitePopulation[getIndex2];
int pos = random.Next(3);
for (int i = 0; i < e1.Count; i++)
{
if (pos == 0)
{
e1[i].roomid = e2[i].roomid;
}
else if (pos == 1)
{
e1[i].weekday = e2[i].weekday;
}
else if (pos == 2)
{
e1[i].slot = e2[i].slot;
}
}
return e1;
}
/**
* 计算课表种群的冲突。
* 返回:精英种群--精英种群中排名第一的染色体若冲突值为0则说明是可以作为最优解返回
* 当被测试课表冲突为0的时候,这个课表就是个符合规定的课表。
* 冲突检测遵循下面几条规则:
* 同一个教室在同一个时间只能有一门课。
* 同一个班级在同一个时间只能有一门课。
* 同一个教师在同一个时间只能有一门课。
* 但是对于目前系统中已经将班级、教师、课程拼成了一条教学任务
* 故只需要满足 同一个教室在同一个时间 只能有一各教学任务
* @param population
* @param elite
* @return
*/
Dictionary<List<Schedule>, int> schedule_cost(List<List<Schedule>> population,int elit)
{
// Hashtable utilMap = new Hashtable();
Dictionary<List<Schedule>, int> utilMap = new Dictionary<List<Schedule>, int>();
Dictionary<List<Schedule>, int> resMap = new Dictionary<List<Schedule>, int>();
List<int> conflicts = new List<int>();
//一个染色体有多长==有多少课程需要安排
int n = population[0].Count;
foreach (List<Schedule> p in population)
{
int conflict = 0;
for (int i = 0; i < n-1; i++)
{
for (int j = i+1; j < n; j++)
{
//check course in same time and same room
//检查冲突 需保证 在同一天 同一节课 下的 同一个教室中没有两个课程
if (p[i].roomid.Equals(p[j].roomid) &&
p[i].weekday == p[j].weekday &&
p[i].slot == p[j].slot)
conflict += 1;
}
}
if( !utilMap.ContainsKey(p))
utilMap.Add(p, conflict);
}
//根据冲突值排序,升序排序,并只取精英个数的量
resMap= utilMap.OrderBy(s => s.Value).Take(elit).ToDictionary(d=>d.Key,d=>d.Value);
return resMap;
}
public void init_population(List<Schedule> schedules,List<String> roomRange)
{
this.population = new List<List<Schedule>>();
for (int i = 0; i < this.popsize; i++)
{
List<Schedule> entity = new List<Schedule>();
for (int j = 0; j < schedules.Count; j++)
{
Schedule temp = schedules.ElementAt(j);
temp.random_init(roomRange,j);
entity.Add(new Schedule()
{etaskid=temp.etaskid,
roomid= temp.roomid,
weekday= temp.weekday,
slot=temp.slot
});
}
this.population.Add(entity);
}
}
}
}