【发布时间】:2018-07-19 06:09:27
【问题描述】:
我正在创建一个程序来优化我的大学为学生的时间表提供的课程。
我将数据解析为以下结构/类:
public struct Subject
{
public int Classes {...}
public int Hours { ... }
public string Name { get; set; }
public string Code { get; set; }
public string Base_Code;
public Campus Campus { get; set; }
public Semester Semester;
}
public struct Timeslot
{
public string ClassType; //code for type: i.e. L for Lecture, W for Workshop
public string Description;
public DayOfWeek Day;
public DateTime Start, Finish;
public List<Tuple<string, string>> weekSpans;
public string Location;
}
public struct Class
{
public Subject subject { get; set; }
public Timeslot time { get; set; }
}
在我本学期的 n 个科目中,我总共有 m 个必修课要参加(讲座 1、2、3,研讨会等)。我将这些存储在“类”类型列表的列表中。
例如:
第 1 讲(主题 1)
- 周一上午 9 点上课
- 周一下午 1 点上课
研讨会 1(主题 2)
- 周一上午 9 点上课
- 周二下午 2 点上课
我目前正在使用 Eric Lippert 的笛卡尔积方法来生成一个包含所有 n 类组合的IEnumerable<IEnumerable<Class>>。
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
// base case:
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach(var sequence in sequences)
{
var s = sequence; // don't close over the loop variable
// recursive case: use SelectMany to build the new product out of the old one
result =
from seq in result
from item in s
select seq.Concat(new[] {item});
}
return result;
}
但是,当我需要从每个 IEnumerable 收集必要的信息以确定哪个时间表符合设定的标准(较短的天数、大部分休息日等)时,就会出现我的问题。尝试遍历所有内容并将它们存储在我的 TimeTable 容器类中确实对存储初始排列所需的内存之上的内存造成负担。
public class TimeTable
{
public IEnumerable<Class> _classes;
public DateTime MinStart { get; private set; }
public DateTime MaxFinish { get; private set; }
public int DaysOff { get; private set; }
public TimeTable(IEnumerable<Class> Classes) { ... }
}
事实上,我的内存猛增到 2GB,然后崩溃。我曾想过通过丢弃包含冲突的时间表来优化排列过程,我知道该怎么做,但我无法弄清楚我可以将代码放入 CartesianProduct 算法的哪个位置,这样它就不会保存在内存中。我还考虑为每个班级分配一个 ID,然后计算排列,但这并没有优化按用户偏好对时间表进行排序的需要。
这是我的第一个个人项目,我必须处理组合学和内存优化,因此非常感谢任何有关如何优化此优化过程的建议和帮助(哈哈!)。
【问题讨论】:
-
这些类型都不应该是结构。它们是可变的,对于结构来说太大了,并且在逻辑上不代表单个值。它们都应该是类。
-
您只是无法将所有这些都存储在内存中。您需要弄清楚如何在任何时候只在内存中拥有恒定数量的排列时找到您想要的信息。排列增长太快,你无法做任何其他事情。
-
除了最小的调度问题外,我们不想生成所有可能的排列。你明白为什么会这样。通常这些问题会受到混合整数规划、约束规划或某种形式的(元)启发式的攻击。
标签: c# optimization memory-management cartesian-product