C# 是否有标准算法将重叠对象平衡到桶中?

C# 是否有标准算法将重叠对象平衡到桶中?,c#,.net,algorithm,combinatorics,C#,.net,Algorithm,Combinatorics,我有一群用户,具有给定的开始和结束时间,例如: { Name = "Peter", StartTime = "10:30", EndTime = "11:00" }, { Name = "Dana", StartTime = "11:00", EndTime = "12:30" }, { Name = "Raymond", StartTime = "10:30", EndTime = "14:00" }, { Name = "Egon", StartTime = "12:00", EndTime

我有一群用户,具有给定的开始和结束时间,例如:

{ Name = "Peter", StartTime = "10:30", EndTime = "11:00" },
{ Name = "Dana", StartTime = "11:00", EndTime = "12:30" },
{ Name = "Raymond", StartTime = "10:30", EndTime = "14:00" },
{ Name = "Egon", StartTime = "12:00", EndTime = "13:00" },
{ Name = "Winston", StartTime = "10:00", EndTime = "12:00" }
我想根据它们重叠的时间(基于可配置的阈值,例如,它们至少需要重叠半小时)将它们放入桶中。我希望水桶最好是4件大,但2-5件的范围都可以接受

在上面的例子中,没有4个人匹配,所以我有一桶3人(彼得、雷蒙德、温斯顿)和一桶2人(达娜、伊贡)

我已经原型化了一种算法,它似乎依赖于机会而不是科学:

  • 按开始时间排序
  • 创建一个空桶
  • 从列表中选择第一个用户
  • 对照bucket中的所有用户检查该用户
  • 如果该用户与bucket中的所有人重叠,则将该用户放入bucket中,并将其从列表中删除
  • 如果bucket的大小是理想的(4),或者如果我循环检查同一个用户超过三次,那么关闭bucket并创建一个新的空bucket
  • 这对于最初的几个桶很有效,但是导致了只有两个人的桶可以更好地组合

    我可以改变算法,从列表中删除所有理想的桶,然后重新洗牌并尝试更多,但我觉得这应该是一个常见的问题——就像工人的轮班作业,或者可能是工作

    有人知道这类问题的标准算法吗


    (标记组合数学,因为我认为这是它适用的数学领域,如果错了请纠正我)

    基于你的问题,我可能会做一些事情,比如首先创建一个名为“Person”pr的类。为该类指定“名称”、“开始时间”和“结束时间”属性

    然后把它们放在Person类型的有序列表中。(另外,我目前将时间存储为双倍。只需将时间的任何小数部分乘以60/100,就可以将它们转换回时间

    接下来,您将创建一个存储桶列表,如果需要,您可以向其中添加新的存储桶。然后,您将根据您定义的阈值对列表进行排序,如果正在比较的两个对象根据该阈值重叠,则这两个对象都将进入该存储桶。如果它们不重叠,则移动到下一个存储桶,如果存在重叠,则将其添加到下一个存储桶直到你到达最后一个桶为止。如果你已经完成了所有的桶并且仍然没有重叠,那么为该对象创建一个新的桶

    class MainFunc
    {    
        static void Main(string[] args)
        {    
    
             //makes a function to check if 2 values overlap over a threshold
             //st stands for start time and et stands for end time
    
             public bool IsWithinThreshold(double st1, double st2, double et1, double et2)
             {
                 double threshold = .5;
                 if(st1 >= et2 || st2 >= et1)
                 {
                     return false
                 }
                 else
                 {
                     if(st1+threshold <= et2 && st1+threshold <= et1 || st2+threshold <= et1 && st2+threshold <=et2)
                     {
                         return true;
                     }
                     else
                     {
                         return false;
                     }
                 }
             }           
            // makes objects of type Person with attributes of name, start time, and end time
    
            Person Peter = new Person();
            Peter.name = "Peter"
            Peter.start_time = 10.5
            Peter.end_time = 11.0
    
            Person Dana = new Person();
            Dana.name = "Dana"
            Peter.start_time = 11.0
            Peter.end_time = 12.5
    
            Person Raymond = new Person();
            Raymond.name = "Raymond"
            Raymond.start_time = 10.5
            Raymond.end_time = 14.0
    
            Person Egon = new Person();
            Egon.name = "Egon"
            Egon.start_time = 12.0
            Egon.end_time = 13.0
    
            Person Winston = new Person();
            Winston.name = "Winston"
            Winston.start_time = 10.0
            Winston.end_time = 12.0
    
            //puts objects of type Person into an unordered list
    
            List<Person> people = new List<Person>();
            people.Add(Peter);
            people.Add(Dana);
            people.Add(Raymond);
            people.Add(Egon);
            people.Add(Winston);
    
            //sets up a list of lists of People (Buckets in our case)
    
            List<List<Person>> Buckets = new List<List<Person>>;
    
            //sets up an intial Bucket and adds the first person on the list to it
    
            List<Person> Bucketinitial = new List<Person>;
            Bucketinitial.add(people[0]);
    
    
            for(var i = 1; i < people.Count; i++)
            {
                for(var j = 0; j< Buckets.count; j++)
                {
                    //sets a checker to make sure that all objects in a given Bucket overlap with the person we are checking
    
                    bool overlap = true;
    
                    for(var k = 0; k< Buckets[k].count; k++)
                    {
                    overlap = overlap & IsWithinThreshold(people[i].start_time,Buckets[j][k].start_time,people[i].end_time,Buckets[j][k].end_time)
                    }
    
                    if (overlap == true)
                    {
                        Buckets[j].add(people[i])
                    }
    
                    //if all the objects in a bucket don't overlap with the person...
                    //... make a new Bucket with that person
                    else
                    {
                        List<Person> NewBucket = new List<Person>;
                        NewBucket.add(people[i]);
                        Buckets.add(NewBucket);
                    }
                }
            }
        }
    }
    
    class MainFunc
    {    
    静态void Main(字符串[]参数)
    {    
    //生成一个函数,用于检查两个值是否在阈值上重叠
    //st代表开始时间,et代表结束时间
    公共布尔值在阈值内(双st1、双st2、双et1、双et2)
    {
    双阈值=.5;
    如果(st1>=et2 | | st2>=et1)
    {
    返回错误
    }
    其他的
    {
    
    if(st1+阈值tl;dr:win(O(排序(n))时间)的动态规划)

    首先,请注意,按开始时间顺序连续扣合是可以的

    建议(碎片整理):
    a、b、c、d
    成为不同的用户,以便
    开始时间(a)≤ 开始时间(b)≤ 开始时间(c)≤ 开始时间(d)
    。如果
    X
    Y
    是有效的存储桶,则
    a、c∈ X
    b,d∈ Y
    ,然后
    X-{c}∪ {b} 
    Y-{a}∪ {d} 
    也是有效的存储桶

    我只知道如何通过冗长的案例分析来证明这一点(略)


    结果是,你可以假装把一个段落分成几行,其中“段落”是按开始时间顺序排列的用户列表,每个“行”是一个桶。根据Knuth和Plass,有一种优化换行的算法,其中给定行的惩罚或多或少是一个任意函数。例如,您可以使4个桶的成本为0,3个桶的成本为1,2个桶的成本为2,1个桶的成本为100。

    您可以修改算法,将区间树合并到加快搜索速度

  • 按开始时间排序
  • 将项目添加到间隔树
  • 创建一个空桶
  • 从列表中选择第一项
  • 使用间隔树的间隔搜索,查找第一个装满存储桶的项目的阈值时间内的最早项目
  • 从列表中删除带扣的项目
  • 如果列表为空,则停止,否则转至步骤4

  • 基本上,您是以间隔步骤(由您可配置的阈值给定)从左向右移动,在移动过程中使用间隔树快速查询最近的项目。

    是否希望仅根据30分钟(阈值)来订购存储桶重叠或基于谁重叠最多?@或避免任何重叠都可以。我们可以调整最小重叠(例如,最小60分钟),但重叠60分钟的人和重叠180分钟的人一样好。我认为间隔树会很好地工作。我做了一个间隔树程序。它肯定没有算法那么干净,但基本上是我下面的答案。*注意,我的间隔可能会因此而变短,所以当你把代码放在你最喜欢的com中时piler,请确保对其进行响应,这样您就有了完美的标记行代码。
    class MainFunc
    {    
        static void Main(string[] args)
        {    
    
             //makes a function to check if 2 values overlap over a threshold
             //st stands for start time and et stands for end time
    
             public bool IsWithinThreshold(double st1, double st2, double et1, double et2)
             {
                 double threshold = .5;
                 if(st1 >= et2 || st2 >= et1)
                 {
                     return false
                 }
                 else
                 {
                     if(st1+threshold <= et2 && st1+threshold <= et1 || st2+threshold <= et1 && st2+threshold <=et2)
                     {
                         return true;
                     }
                     else
                     {
                         return false;
                     }
                 }
             }           
            // makes objects of type Person with attributes of name, start time, and end time
    
            Person Peter = new Person();
            Peter.name = "Peter"
            Peter.start_time = 10.5
            Peter.end_time = 11.0
    
            Person Dana = new Person();
            Dana.name = "Dana"
            Peter.start_time = 11.0
            Peter.end_time = 12.5
    
            Person Raymond = new Person();
            Raymond.name = "Raymond"
            Raymond.start_time = 10.5
            Raymond.end_time = 14.0
    
            Person Egon = new Person();
            Egon.name = "Egon"
            Egon.start_time = 12.0
            Egon.end_time = 13.0
    
            Person Winston = new Person();
            Winston.name = "Winston"
            Winston.start_time = 10.0
            Winston.end_time = 12.0
    
            //puts objects of type Person into an unordered list
    
            List<Person> people = new List<Person>();
            people.Add(Peter);
            people.Add(Dana);
            people.Add(Raymond);
            people.Add(Egon);
            people.Add(Winston);
    
            //sets up a list of lists of People (Buckets in our case)
    
            List<List<Person>> Buckets = new List<List<Person>>;
    
            //sets up an intial Bucket and adds the first person on the list to it
    
            List<Person> Bucketinitial = new List<Person>;
            Bucketinitial.add(people[0]);
    
    
            for(var i = 1; i < people.Count; i++)
            {
                for(var j = 0; j< Buckets.count; j++)
                {
                    //sets a checker to make sure that all objects in a given Bucket overlap with the person we are checking
    
                    bool overlap = true;
    
                    for(var k = 0; k< Buckets[k].count; k++)
                    {
                    overlap = overlap & IsWithinThreshold(people[i].start_time,Buckets[j][k].start_time,people[i].end_time,Buckets[j][k].end_time)
                    }
    
                    if (overlap == true)
                    {
                        Buckets[j].add(people[i])
                    }
    
                    //if all the objects in a bucket don't overlap with the person...
                    //... make a new Bucket with that person
                    else
                    {
                        List<Person> NewBucket = new List<Person>;
                        NewBucket.add(people[i]);
                        Buckets.add(NewBucket);
                    }
                }
            }
        }
    }