【问题标题】:How to achieve the below logic in C#?如何在 C# 中实现以下逻辑?
【发布时间】:2011-04-05 09:54:08
【问题描述】:

我需要为每个时间表分配频道。可以有与分配给客户的渠道数量一样多的并发事件。即,如果为客户分配了 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
}

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

【问题讨论】:

  • 请贴出你目前写的代码。人们通常不喜欢只为您编写代码。事实上,这是一个工作描述,而不是一个问题。

标签: c# asp.net logic


【解决方案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;
        } 
    }
}

【讨论】:

    【解决方案2】:

    在我看来有点类似于 Vehicle Routing Problem。通道与车辆相同,事件类似于有向无环图中的节点,当且仅当第一个事件在第二个事件开始之前完成时,边缘从一个事件指向另一个事件。

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

    【讨论】:

      【解决方案3】:

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

      这是一个 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
      

      所有的事件都适合。

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

      【讨论】:

      • 你想表达什么?
      • 当您急切地分配事件(到第一个空闲频道)时,您的算法的结果取决于您添加事件的顺序。您最终可能会遇到这样的情况,如果您以不同的顺序处理事件,则可以将它们放入可用的通道中,但是由于您按此顺序处理它们,因此有些事件将不适合任何地方。
      【解决方案4】:

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

        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;
                  }
      
              }
      
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多