C# 使用多个重叠可能性的两个列表的一对一匹配算法
这是一个真正的挑战: 我有一份家庭名单和一份帮手名单。每个家庭和每个帮手都有各自需要帮助或可以提供帮助的时间段 举例说明:C# 使用多个重叠可能性的两个列表的一对一匹配算法,c#,algorithm,sorting,C#,Algorithm,Sorting,这是一个真正的挑战: 我有一份家庭名单和一份帮手名单。每个家庭和每个帮手都有各自需要帮助或可以提供帮助的时间段 举例说明: Family 1: 11:00 - 12:30 Family 2: 13:00 - 18:00 Family 3: 8:15 - 9:30 Helper 1: 14:30 - 16:30 Helper 2: 17:00 - 19:30 Helper 3: 16:45 - 17:45 Helper 4: 17:00 - 18:00 这些条目的数量可能相等,也可能不相等;它
Family 1: 11:00 - 12:30
Family 2: 13:00 - 18:00
Family 3: 8:15 - 9:30
Helper 1: 14:30 - 16:30
Helper 2: 17:00 - 19:30
Helper 3: 16:45 - 17:45
Helper 4: 17:00 - 18:00
这些条目的数量可能相等,也可能不相等;它们在列表内或列表间可能重叠,也可能不重叠
我想做的是找到一种算法,在助手和家庭之间提供最佳覆盖。这与大多数时间表算法不同,因为它是一种使用潜在多对多的一对一匹配。如果在“族”或“助手”中存在完全匹配的,而没有任何平行条目,则会将其保存并从列表中删除,因为这是该时间段的唯一可能性。
然而,我正在努力寻找下一个基本情况。
我不想使用最大优先法,因为这并不总是最优的;最早完成时间/贪婪算法都不是
如果我知道处理helper条目的顺序(即首先打包哪些条目),那么装箱算法似乎会有所帮助
我一直在为此伤脑筋;尽管研究表明它是NP难的,但我想还是有某种解决方案的。好吧,我只需要将它们的时间转换成整数形式的分钟,如下所示:
//families[n][start, end]
int[][] families = new int[][] {
new int[] {660, 780},
new int[] {780, 1080},
new int[] {495, 570}
};
//helpers[n][start, end]
int[][] helpers = new int[][] {
new int[] {870, 990},
new int[] {1020, 1170},
new int[] {1005, 1065},
new int[] {1020, 1080}
};
//check for the optimal helper
{
bool foundOptimalHelper = false;
for (int k = 0; k < helpers.Length; k++) {
if (families[i][0] >= helpers[k][0] && families[i][1] <= helpers[k][1]) {
//check if the helper is occupied
if (!CheckIfHelperAvable(k, families[i][0], families[i][1]))
break;
foundOptimalHelper = true;
Console.WriteLine("\thelper {0} is optimal during that time period", k);
helpersSchedule[k].Add(new int[] { i, families[i][0], families[i][1] });
break;
}
}
if (foundOptimalHelper)
continue;
}
我真的不知道你在寻找什么答案,但我相信这有点像帮助者的时间表。
然后我们需要一种存储日程数据的方法。我们可以通过以下方式实现这一点:
//helpersSchedule[helper][events][Family, start, end]
List<List<int[]>> helpersSchedule = new List<List<int[]>>();
现在我们有了真正的魔法
它将首先尝试找到一个在开始时间可用的助手,然后尝试获得一个具有壁橱开始时间的助手。在剩下的时间里,它将继续调用自己
void TryToCoverTimePeriod(int family, int timeStart = 0, int timeEnd = 1440)
{
List<int[]> helperTimeCoverege = new List<int[]>(); //list of helper with coverege time that start before timeStart
List<int[]> helperTimeCoveregeSecondary = new List<int[]>(); //list of helper with start time that start after timeStart
for (int i = 0; i < helpers.Length; i++) {
if (helpers[i][0] <= timeStart && helpers[i][1] > timeStart) {
if (CheckIfHelperAvable(i, timeStart, Math.Min(timeEnd, helpers[i][1])))
helperTimeCoverege.Add(new int[] { i, Math.Min(timeEnd, helpers[i][1]) - timeStart });
} else if (helpers[i][1] < timeEnd) {
if (CheckIfHelperAvable(i, helpers[i][0], Math.Min(timeEnd, helpers[i][1])))
helperTimeCoveregeSecondary.Add(new int[] { i, helpers[i][0] });
}
}
int[] bestHelper = new int[] { -1, 0 };
if (helperTimeCoverege.Count > 0) {
//get best helper
foreach (int[] helper in helperTimeCoverege) {
if (helper[1] > bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, timeStart, timeStart + bestHelper[1] });
if (timeStart + bestHelper[1] < timeEnd) {
TryToCoverTimePeriod(family, timeStart + bestHelper[1], timeEnd); //not enough, need more helpers
}
} else {
//get best helper
foreach (int[] helper in helperTimeCoveregeSecondary) {
if (helper[1] > bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, bestHelper[1], Math.Min(helpers[bestHelper[0]][1], timeEnd) });
if (Math.Min(helpers[bestHelper[0]][1], timeEnd) < timeEnd) {
TryToCoverTimePeriod(family, Math.Min(helpers[bestHelper[0]][1], timeEnd), timeEnd); //not enough, need more helpers
}
}
}
void TryToCoverTimePeriod(int系列,int timeStart=0,int timeEnd=1440)
{
List HELPERTIMECOVERGE=new List();//在timeStart之前开始使用coverege time的帮助程序列表
List helpertimecovergesecondary=new List();//在timeStart之后开始的具有开始时间的帮助程序列表
for(int i=0;i0){
//找最好的帮手
foreach(helperItemOverge中的int[]helper){
if(helper[1]>bestHelper[1]){
最佳助手[0]=助手[0];
最佳助手[1]=助手[1];
}
}
//设定时间表
helpersSchedule[bestHelper[0]]添加(新的int[]{family,timeStart,timeStart+bestHelper[1]});
if(timeStart+bestHelper[1]bestHelper[1]){
最佳助手[0]=助手[0];
最佳助手[1]=助手[1];
}
}
//设定时间表
helpersSchedule[bestHelper[0]].Add(新int[]{family,bestHelper[1],Math.Min(helpers[bestHelper[0]][1],timeEnd)});
if(Math.Min(helpers[bestHelper[0]][1],timeEnd)
要显示数据,请执行以下操作
//display helper's Schedule
Console.WriteLine("--------------------------------------");
for (int i = 0; i < helpersSchedule.Count; i++) {
Console.WriteLine("Helper n.{0}:", i);
foreach (int[] helperEvent in helpersSchedule[i]) {
//Console.WriteLine("\tfamily n.{0}: {1} - {2}", helperEvent[0], helperEvent[1], helperEvent[2]);
Console.WriteLine("\tfamily n.{0}: {1:00}:{2:00} - {3:00}:{4:00}", helperEvent[0], helperEvent[1] / 60, helperEvent[1] % 60, helperEvent[2] / 60, helperEvent[2] % 60);
}
}
Console.ReadKey();
//显示助手的日程安排
Console.WriteLine(“---------------------------------------------”);
for(int i=0;i
结果如下。
这是当前家庭和帮手的最佳解决方案
这是洞的计划,享受吧
class Program
{
//families[n][start, end]
static int[][] families = new int[][] {
new int[] {660, 780},
new int[] {780, 1080},
new int[] {495, 570},
};
//helpers[n][start, end]
static int[][] helpers = new int[][] {
new int[] {870, 990},
new int[] {1020, 1170},
new int[] {1005, 1065},
new int[] {1020, 1080}
};
//helpersSchedule[helper][events][Family, start, end]
static List<List<int[]>> helpersSchedule = new List<List<int[]>>();
static void Main(string[] args)
{
int workTimeStart = 1440;
int workTimeEnd = 0;
for (int i = 0; i < helpers.Length; i++) {
helpersSchedule.Add(new List<int[]>());
if (helpers[i][0] < workTimeStart)
workTimeStart = helpers[i][0];
else if (helpers[i][1] > workTimeEnd)
workTimeEnd = helpers[i][1];
}
for (int i = 0; i < families.Length; i++) {
//Console.WriteLine("calculating for family n.{0}", i);
if (workTimeStart > families[i][1] || workTimeEnd < families[i][0]) {
//Console.WriteLine("\tno helper available during that time period");
continue;
}
/*
//check for optimal helper
{
bool foundOptimalHelper = false;
for (int k = 0; k < helpers.Length; k++) {
if (families[i][0] >= helpers[k][0] && families[i][1] <= helpers[k][1]) {
//check if the helper is occupied
if (!CheckIfHelperAvable(k, families[i][0], families[i][1]))
break;
foundOptimalHelper = true;
Console.WriteLine("\thelper {0} is optimal during that time period", k);
helpersSchedule[k].Add(new int[] { i, families[i][0], families[i][1] });
break;
}
}
if (foundOptimalHelper)
continue;
}
*/
//cover time
TryToCoverTimePeriod(i, families[i][0], families[i][1]);
}
//display helper's Schedule
Console.WriteLine("--------------------------------------");
for (int i = 0; i < helpersSchedule.Count; i++) {
Console.WriteLine("Helper n.{0}:", i);
foreach (int[] helperEvent in helpersSchedule[i]) {
//Console.WriteLine("\tfamily n.{0}: {1} - {2}", helperEvent[0], helperEvent[1], helperEvent[2]);
Console.WriteLine("\tfamily n.{0}: {1:00}:{2:00} - {3:00}:{4:00}", helperEvent[0], helperEvent[1] / 60, helperEvent[1] % 60, helperEvent[2] / 60, helperEvent[2] % 60);
}
}
Console.ReadKey();
}
static bool CheckIfHelperAvable(int helper, int timeStart = 0, int timeEnd = 1440)
{
foreach (int[] helpEvent in helpersSchedule[helper]) {
if (timeEnd < helpEvent[2] || timeStart > helpEvent[1]) {
continue;
} else {
//helper is occupied during that time period
return false;
}
}
return true;
}
static void TryToCoverTimePeriod(int family, int timeStart = 0, int timeEnd = 1440)
{
List<int[]> helperTimeCoverege = new List<int[]>(); //list of helper with coverege time that start before timeStart
List<int[]> helperTimeCoveregeSecondary = new List<int[]>(); //list of helper with start time that start after timeStart
for (int i = 0; i < helpers.Length; i++) {
if (helpers[i][0] <= timeStart && helpers[i][1] > timeStart) {
if (CheckIfHelperAvable(i, timeStart, Math.Min(timeEnd, helpers[i][1])))
helperTimeCoverege.Add(new int[] { i, Math.Min(timeEnd, helpers[i][1]) - timeStart });
} else if (helpers[i][0] < timeEnd) {
if (CheckIfHelperAvable(i, helpers[i][0], Math.Min(timeEnd, helpers[i][1])))
helperTimeCoveregeSecondary.Add(new int[] { i, helpers[i][0] });
}
}
if (helperTimeCoverege.Count > 0) {
int[] bestHelper = new int[] { -1, 0 };
//get best helper
foreach (int[] helper in helperTimeCoverege) {
if (helper[1] > bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, timeStart, timeStart + bestHelper[1] });
if (timeStart + bestHelper[1] < timeEnd) {
TryToCoverTimePeriod(family, timeStart + bestHelper[1], timeEnd); //not enough, need more helpers
}
} else if (helperTimeCoveregeSecondary.Count > 0) {
int[] bestHelper = new int[] { -1, 1440 };
//get best helper
foreach (int[] helper in helperTimeCoveregeSecondary) {
if (helper[1] < bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, bestHelper[1], Math.Min(helpers[bestHelper[0]][1], timeEnd) });
if (Math.Min(helpers[bestHelper[0]][1], timeEnd) < timeEnd) {
TryToCoverTimePeriod(family, Math.Min(helpers[bestHelper[0]][1], timeEnd), timeEnd); //not enough, need more helpers
}
}
}
}
类程序
{
//家庭[开始,结束]
静态int[][]族=新int[][]{
新int[]{660780},
新的int[]{7801080},
新的int[]{495570},
};
//助手[n][开始,结束]
静态int[]helpers=新int[]{
新int[]{870990},
新的int[]{1020,1170},
新的int[]{10051065},
新int[]{10201080}
};
//助手计划[助手][事件][家庭,开始,结束]
静态列表帮助程序Schedule=新列表();
静态void Main(字符串[]参数)
{
int workTimeStart=1440;
int workTimeEnd=0;
for(int i=0;iworkTimeEnd)
workTimeEnd=helpers[i][1];
}
对于(int i=0;ifamilies[i][1]| | workTimeEnd //cover time
TryToCoverTimePeriod(i, families[i][0], families[i][1]);
}
void TryToCoverTimePeriod(int family, int timeStart = 0, int timeEnd = 1440)
{
List<int[]> helperTimeCoverege = new List<int[]>(); //list of helper with coverege time that start before timeStart
List<int[]> helperTimeCoveregeSecondary = new List<int[]>(); //list of helper with start time that start after timeStart
for (int i = 0; i < helpers.Length; i++) {
if (helpers[i][0] <= timeStart && helpers[i][1] > timeStart) {
if (CheckIfHelperAvable(i, timeStart, Math.Min(timeEnd, helpers[i][1])))
helperTimeCoverege.Add(new int[] { i, Math.Min(timeEnd, helpers[i][1]) - timeStart });
} else if (helpers[i][1] < timeEnd) {
if (CheckIfHelperAvable(i, helpers[i][0], Math.Min(timeEnd, helpers[i][1])))
helperTimeCoveregeSecondary.Add(new int[] { i, helpers[i][0] });
}
}
int[] bestHelper = new int[] { -1, 0 };
if (helperTimeCoverege.Count > 0) {
//get best helper
foreach (int[] helper in helperTimeCoverege) {
if (helper[1] > bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, timeStart, timeStart + bestHelper[1] });
if (timeStart + bestHelper[1] < timeEnd) {
TryToCoverTimePeriod(family, timeStart + bestHelper[1], timeEnd); //not enough, need more helpers
}
} else {
//get best helper
foreach (int[] helper in helperTimeCoveregeSecondary) {
if (helper[1] > bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, bestHelper[1], Math.Min(helpers[bestHelper[0]][1], timeEnd) });
if (Math.Min(helpers[bestHelper[0]][1], timeEnd) < timeEnd) {
TryToCoverTimePeriod(family, Math.Min(helpers[bestHelper[0]][1], timeEnd), timeEnd); //not enough, need more helpers
}
}
}
//display helper's Schedule
Console.WriteLine("--------------------------------------");
for (int i = 0; i < helpersSchedule.Count; i++) {
Console.WriteLine("Helper n.{0}:", i);
foreach (int[] helperEvent in helpersSchedule[i]) {
//Console.WriteLine("\tfamily n.{0}: {1} - {2}", helperEvent[0], helperEvent[1], helperEvent[2]);
Console.WriteLine("\tfamily n.{0}: {1:00}:{2:00} - {3:00}:{4:00}", helperEvent[0], helperEvent[1] / 60, helperEvent[1] % 60, helperEvent[2] / 60, helperEvent[2] % 60);
}
}
Console.ReadKey();
class Program
{
//families[n][start, end]
static int[][] families = new int[][] {
new int[] {660, 780},
new int[] {780, 1080},
new int[] {495, 570},
};
//helpers[n][start, end]
static int[][] helpers = new int[][] {
new int[] {870, 990},
new int[] {1020, 1170},
new int[] {1005, 1065},
new int[] {1020, 1080}
};
//helpersSchedule[helper][events][Family, start, end]
static List<List<int[]>> helpersSchedule = new List<List<int[]>>();
static void Main(string[] args)
{
int workTimeStart = 1440;
int workTimeEnd = 0;
for (int i = 0; i < helpers.Length; i++) {
helpersSchedule.Add(new List<int[]>());
if (helpers[i][0] < workTimeStart)
workTimeStart = helpers[i][0];
else if (helpers[i][1] > workTimeEnd)
workTimeEnd = helpers[i][1];
}
for (int i = 0; i < families.Length; i++) {
//Console.WriteLine("calculating for family n.{0}", i);
if (workTimeStart > families[i][1] || workTimeEnd < families[i][0]) {
//Console.WriteLine("\tno helper available during that time period");
continue;
}
/*
//check for optimal helper
{
bool foundOptimalHelper = false;
for (int k = 0; k < helpers.Length; k++) {
if (families[i][0] >= helpers[k][0] && families[i][1] <= helpers[k][1]) {
//check if the helper is occupied
if (!CheckIfHelperAvable(k, families[i][0], families[i][1]))
break;
foundOptimalHelper = true;
Console.WriteLine("\thelper {0} is optimal during that time period", k);
helpersSchedule[k].Add(new int[] { i, families[i][0], families[i][1] });
break;
}
}
if (foundOptimalHelper)
continue;
}
*/
//cover time
TryToCoverTimePeriod(i, families[i][0], families[i][1]);
}
//display helper's Schedule
Console.WriteLine("--------------------------------------");
for (int i = 0; i < helpersSchedule.Count; i++) {
Console.WriteLine("Helper n.{0}:", i);
foreach (int[] helperEvent in helpersSchedule[i]) {
//Console.WriteLine("\tfamily n.{0}: {1} - {2}", helperEvent[0], helperEvent[1], helperEvent[2]);
Console.WriteLine("\tfamily n.{0}: {1:00}:{2:00} - {3:00}:{4:00}", helperEvent[0], helperEvent[1] / 60, helperEvent[1] % 60, helperEvent[2] / 60, helperEvent[2] % 60);
}
}
Console.ReadKey();
}
static bool CheckIfHelperAvable(int helper, int timeStart = 0, int timeEnd = 1440)
{
foreach (int[] helpEvent in helpersSchedule[helper]) {
if (timeEnd < helpEvent[2] || timeStart > helpEvent[1]) {
continue;
} else {
//helper is occupied during that time period
return false;
}
}
return true;
}
static void TryToCoverTimePeriod(int family, int timeStart = 0, int timeEnd = 1440)
{
List<int[]> helperTimeCoverege = new List<int[]>(); //list of helper with coverege time that start before timeStart
List<int[]> helperTimeCoveregeSecondary = new List<int[]>(); //list of helper with start time that start after timeStart
for (int i = 0; i < helpers.Length; i++) {
if (helpers[i][0] <= timeStart && helpers[i][1] > timeStart) {
if (CheckIfHelperAvable(i, timeStart, Math.Min(timeEnd, helpers[i][1])))
helperTimeCoverege.Add(new int[] { i, Math.Min(timeEnd, helpers[i][1]) - timeStart });
} else if (helpers[i][0] < timeEnd) {
if (CheckIfHelperAvable(i, helpers[i][0], Math.Min(timeEnd, helpers[i][1])))
helperTimeCoveregeSecondary.Add(new int[] { i, helpers[i][0] });
}
}
if (helperTimeCoverege.Count > 0) {
int[] bestHelper = new int[] { -1, 0 };
//get best helper
foreach (int[] helper in helperTimeCoverege) {
if (helper[1] > bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, timeStart, timeStart + bestHelper[1] });
if (timeStart + bestHelper[1] < timeEnd) {
TryToCoverTimePeriod(family, timeStart + bestHelper[1], timeEnd); //not enough, need more helpers
}
} else if (helperTimeCoveregeSecondary.Count > 0) {
int[] bestHelper = new int[] { -1, 1440 };
//get best helper
foreach (int[] helper in helperTimeCoveregeSecondary) {
if (helper[1] < bestHelper[1]) {
bestHelper[0] = helper[0];
bestHelper[1] = helper[1];
}
}
//setting schedule
helpersSchedule[bestHelper[0]].Add(new int[] { family, bestHelper[1], Math.Min(helpers[bestHelper[0]][1], timeEnd) });
if (Math.Min(helpers[bestHelper[0]][1], timeEnd) < timeEnd) {
TryToCoverTimePeriod(family, Math.Min(helpers[bestHelper[0]][1], timeEnd), timeEnd); //not enough, need more helpers
}
}
}
}