喵呜喵5 发表于 2014-11-19 00:33
好吧...直接带数字比较容易理解
有10门课,50名学生,5周时间
喵呜喵5 发表于 2014-11-19 14:51
每名学生的课程之前已经通过随机的方式选好了,
就是说,学生先通过抽签选好了自己总共要上的课程,之后 ...
IMG_20141119_185029.jpg (490.76 KB, 下载次数: 32)
taroxd 发表于 2014-11-19 17:57
首先声明,我没学过算法,也没参加过信息竞赛,所以别抱太大指望。
这段代码是自修课上写的,无环境测试, ...
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { // 问题参数(其实是个命名空间,C#规定namespace结构下不能有常量) class Parameters { // 课程总数 public const int CourseNumber = 10; // 学生总数 public const int StudentNumber = 50; // 每个课程人数限制 public const int CourseLimit = 5; // 持续的周数(这个也可以理解为学生选的课程数目) public const int Weeks = 5; } class CourseMonitor { public int Energy; public int[,] Data; public int[,] Schedule; public CourseMonitor() { this.Energy = 0; this.Data = new int[Parameters.CourseNumber, Parameters.Weeks]; this.Schedule = null; } // 根据课程排列计算每门课每周理论上课人数(即假定没有人数限制) public void Check() { if (this.Schedule == null) return; for (int i = 0; i < this.Schedule.GetLength(0); i++) { for (int j = 0; j < this.Schedule.GetLength(1); j++) { this.Data[Schedule[i, j], j] += 1; } } foreach (int n in this.Data) this.Energy += n > Parameters.CourseLimit ? Parameters.CourseLimit : n; } } // 模拟退火参数,实际是对模拟退火算法的刻画 class SAParameters { // 起始温度 public const double StartTemp = 300; // 在每个温度下的迭代次数 public const int Iterate = 500; // 温度衰减比率 public const double DecreaseRatio = 0.85; // 终止温度 public const double FinalTemp = 0.05; } class Program { static Random rnd = new Random(); static void Main(string[] args) { CourseMonitor monitor = new CourseMonitor(); monitor.Schedule = new int[Parameters.StudentNumber, Parameters.Weeks]; InitSchedule(monitor.Schedule); monitor.Check(); double temp = SAParameters.StartTemp; int newEnergy = 0, course1, course2; int[] swapArr = new int[3]; bool terminate = false; while (temp > SAParameters.FinalTemp && !terminate) { for (int i = 0; i < SAParameters.Iterate; i++) { if (monitor.Energy == Parameters.StudentNumber * Parameters.Weeks) { terminate = true; break; } newEnergy = monitor.Energy; GenerateSwap(swapArr); course1 = monitor.Schedule[swapArr[0], swapArr[1]]; course2 = monitor.Schedule[swapArr[0], swapArr[2]]; if (monitor.Data[course1, swapArr[1]] <= Parameters.CourseLimit) newEnergy -= 1; if (monitor.Data[course2, swapArr[2]] <= Parameters.CourseLimit) newEnergy -= 1; if (monitor.Data[course1, swapArr[2]] < Parameters.CourseLimit) newEnergy += 1; if (monitor.Data[course2, swapArr[1]] < Parameters.CourseLimit) newEnergy += 1; if (newEnergy > monitor.Energy || rnd.NextDouble() < Math.Exp((newEnergy - monitor.Energy) / temp)) { monitor.Energy = newEnergy; monitor.Data[course1, swapArr[1]] -= 1; monitor.Data[course2, swapArr[2]] -= 1; monitor.Data[course1, swapArr[2]] += 1; monitor.Data[course2, swapArr[1]] += 1; Swap(monitor.Schedule, swapArr); } } temp *= SAParameters.DecreaseRatio; } Print(monitor.Schedule); } // 随机初始化 static void InitSchedule(int[,] schedule) { int r; int[] dummy = new int[Parameters.Weeks]; for (int i = 0; i < Parameters.StudentNumber; i++) { for (int k = 0; k < dummy.Length; k++) dummy[k] = -1; for (int j = 0; j < Parameters.Weeks; j++) { while (true) { r = rnd.Next(Parameters.CourseNumber); if (dummy.All<int>(a => a != r)) { dummy[j] = r; break; } } } for (int k = 0; k < dummy.Length; k++) schedule[i, k] = dummy[k]; } } // 产生简单变换 static void GenerateSwap(int[] result) { result[0] = rnd.Next(Parameters.StudentNumber); result[1] = rnd.Next(Parameters.Weeks); while (result[1] == (result[2] = rnd.Next(Parameters.Weeks))) ; } // 根据变换对课程排列进行交换 static void Swap(int[,] data, int[] swapArr) { int temp = data[swapArr[0], swapArr[1]]; data[swapArr[0], swapArr[1]] = data[swapArr[0], swapArr[2]]; data[swapArr[0], swapArr[2]] = temp; } static void Print(int[,] data) { for (int i = 0; i < data.GetLength(0); i++) { for (int j = 0; j < data.GetLength(1); j++) { System.Console.Write("" + data[i, j] + '\t'); } System.Console.Write('\n'); } } } }
欢迎光临 Project1 (https://rpg.blue/) | Powered by Discuz! X3.1 |