如何在C#中实现以下逻辑?

时间:2011-04-05 09:54:09

标签: c# asp.net logic

我需要为每个时间表分配频道。可以存在与为客户分配的通道数一样多的并发事件。即如果客户被分配了3个频道,那么他可以有3个并发事件。如果一个频道被分配给一个事件,那么相同的频道不能分配给同一时间内的另一个事件,但如果时间不同,可以将同一个频道分配给另一个事件。

频道表

ID Name
1  Name1
2  Name2
3  Name3

活动表

ID EventName StartTime EndTime ChannelID
1  Event1    11:30AM   12PM    1
2  Event2    11:30AM   11:40AM 2
3  Event3    11:40AM   12PM    2
4  Event4    12PM      12:30PM 1 0r 2
5  Event5    11:30AM   12:30PM 3

以上是预期的产出。

我试过嵌套的foreachloop一个用于频道,另一个用于evets,但是无法实现并且复杂性非常高。如何实现这个逻辑?

伪代码:

for each channel
{
    foreach existing events
    {
        if(sametime && same channel)
            {
             go for next channel
            }
        break;
    }
assign current channel to new event
}

当我尝试创建第3个事件时失败。

4 个答案:

答案 0 :(得分:1)

您可以循环浏览事件以将频道分配给事件,请查看下面的伪代码:

foreach events 
{ 
    foreach channels 
    { 
        if currentChannel is assigned 
        { 
            foreach assignedEvents 
            { 
                if assignedTime = currentEventTime 
                    go to next Channel (continue)
            } 
            currentEvent.Channel = currentChannel 
            break;
        } 
        else 
        { 
            currentEvent.Channel = currentChannel 
            break;
        } 
    }
}

答案 1 :(得分:0)

你必须产生所有可能性,并选择最好的。

这是NP完全问题,所以没有办法快速和正确地做到这一点 - 要么你通过一些启发式快速做到这一点,但是你不知道它是否真的做得最好,或者你做到了慢,我的意思是慢,但你确定结果是最佳的。

取决于您的数据大小。

编辑: 举例说明,仅将事件分配给第一个空闲频道并不总是有效。

我们有3个频道: Ch1,Ch2,Ch3

我们必须安排6个活动:

E1-2 - starts at 1:00 ends at 2:59
E1-3 - starts at 1:00 ends at 3:59
E1-3 - starts at 1:00 ends at 3:59
E4 - starts at 4:00 ends at 4:59
E4 - starts at 4:00 ends at 4:59
E3-4 - starts at 3:00 ends at 4:59

如果你只是分配到第一个免费的地方,你最终会得到:

Ch1: E1-2, E4
Ch2: E1-3, E4
Ch3: E1-3
and no place for E3-4

如果您按不同的顺序分配它们,您将获得

Ch1: E1-2, E3-4
Ch2: E1-3, E4
Ch3: E1-3, E4

所有事件都适合。

所以你必须以某种方式做回溯。

答案 2 :(得分:0)

看起来有点类似于车辆路线问题。通道与车辆相同,事件就像有向非循环图中的节点,边缘从一个事件传递到另一个事件,当且仅当第一个事件比第二个事件开始时更早结束。

您应该能够找到解决此问题的公开算法。

答案 3 :(得分:0)

我修复了代码中的一些问题。我认为现在应该可行了

  using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

namespace ChannelAllocator
{

    class Program
    {
        const int _numberOfChannels = 10;
        static void Main(string[] args)
        {
            Dictionary<int, List<TimeSlot>> occupiedChannels = new Dictionary<int, List<TimeSlot>>();

            for (int i = 1; i <= _numberOfChannels; i++)
            {

                occupiedChannels.Add(i, new List<TimeSlot>());
            }

            /** Example **/
            TimeSpan start = DateTime.Now.AddHours(-1.0).TimeOfDay;
            TimeSpan end = DateTime.Now.TimeOfDay;
            AssignChannel(occupiedChannels, ref start, ref end);           

        }

        private static bool AssignChannel(Dictionary<int, List<TimeSlot>> occupiedChannels, ref TimeSpan start, ref TimeSpan end)
        {
            List<int> channels = occupiedChannels.Keys.ToList();
            if (start >= end )
                return false;
            foreach (var item in channels)
            {
                List<TimeSlot> slots = occupiedChannels[item];
                if (slots.Count == 0)
                {
                    occupiedChannels[item].Add(new TimeSlot(start, end));
                    return true;

                }
                else
                {
                    bool available = false ;
                    foreach (var slot in slots)
                    {
                        TimeSpan channelStartTime = slot.StartTime;
                        TimeSpan channelEndTime = slot.EndTime;

                        if (start >= channelStartTime && end <= channelEndTime ||
                            start <= channelStartTime && end <= channelEndTime && end >= channelStartTime
                            || end >= channelEndTime && start >= channelStartTime && start <= channelEndTime)
                        {
                            available = false;
                            break;    
                        }
                        else { 
                            available = true; 
                        }
                    }
                    if (available)
                    {
                        occupiedChannels[item].Add(new TimeSlot(start, end));
                        return true;
                    }

                }
            }
            return false;
        }

        private class TimeSlot
        {
            public TimeSpan StartTime;
            public TimeSpan EndTime;
            public TimeSlot(TimeSpan start, TimeSpan end)
            {
                StartTime = start;
                EndTime = end;
            }

        }

    }
}