Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我如何生成一个";“社交高尔夫球手”;工人座位安排矩阵?_C#_Sql_Oracle_Select_Permutation - Fatal编程技术网

C# 我如何生成一个";“社交高尔夫球手”;工人座位安排矩阵?

C# 我如何生成一个";“社交高尔夫球手”;工人座位安排矩阵?,c#,sql,oracle,select,permutation,C#,Sql,Oracle,Select,Permutation,这是一个挑战。我有一家有320人的公司。我最近实施了一个目标管理(MBO)计划,每个员工都被分配每月完成一个目标。其中一个经常出现的目标是准时上班,参加每天早上30分钟的咖啡和杜努特会议。会议在我们有50张桌子的餐厅举行。每张桌子最多可容纳8人。每个工作日正负80个座位都是空的,因为目前最多可容纳400人。我想生成一个循环的座位安排,这样每个人都可以轮流与其他人会面和合作 (编辑)规则:每个工作日需要8人的独特团队。在用尽所有可能的排列之前,一个人不能再与过去共坐过的其他人坐在一起 编辑:所需结

这是一个挑战。我有一家有320人的公司。我最近实施了一个目标管理(MBO)计划,每个员工都被分配每月完成一个目标。其中一个经常出现的目标是准时上班,参加每天早上30分钟的咖啡和杜努特会议。会议在我们有50张桌子的餐厅举行。每张桌子最多可容纳8人。每个工作日正负80个座位都是空的,因为目前最多可容纳400人。我想生成一个循环的座位安排,这样每个人都可以轮流与其他人会面和合作

(编辑)规则:每个工作日需要8人的独特团队。在用尽所有可能的排列之前,一个人不能再与过去共坐过的其他人坐在一起

编辑:所需结果的示例如下:

Day 1: 

Table 1 will seat worker numbers 1,2,3,4,5,6,7,8.
Table 2 will seat worker numbers 9.10,11,12,13,14,15,16
...
Table 50 will seat worker numbers 313,314,315,316,317,318,319,320


**NOTE:**
(So, the next workday and thereafter, workers 1 through 8 cannot ever be seated with 
any other workers from that same set until all possible permutations have been
exhausted).

Day 2:

Table 1 will seat worker numbers 1,17,18,19,20,21,22,23
Table 2 will seat worker numbers 2,10,24,25,26,27,28,29
...
Table 50 will seat worker numbers 305,306,307,308,309,310,311,312


Day N: 
.
.
...
.
在用尽所有可能的唯一集合(排列)之前,每个集合(数组)中的8个辅助编号(元素)都不能重复。然后,循环又重新开始,也许会改变元素,只有这样,一个工人才会和他们以前见过的另一个工人坐在一起。然后我会给每个员工发电子邮件,告诉他们下一个工作日要坐的桌子。每个工人都不知道还有谁坐在他们指定的桌子旁,直到他们到达桌子。只有我有完整的座位安排名册。(这是一种“音乐椅”游戏)

这不是练习或学校作业。一位使用APL编程语言的朋友告诉我,她可以用一行代码生成所需的结果,但我们只使用基于SQL的DBMS(IBM Informix 11.70和Oracle 11)

因此,我有一个包含以下列的SQL表:

employee.id        INT      {unique primary key}
employee.FullName  VARCHAR
...
以下一行APL编程代码生成矩阵置换:

pmat2←{{,[⍳2]↑(⊂⊂⎕io,1+⍵)⌷¨⍒¨↓∘.=⍨⍳1+1↓⍴⍵}⍣⍵⍉⍪⍬}
在SQL中,我能用一条SELECT语句生成所需的结果吗?我需要多条SELECT INTO TEMP语句吗?还是需要一个存储过程来获得所需的结果

我的SELECT语句或SP应该是什么样子

编辑:如果所需的结果不能用SQL实现,那么是否可以用一个称为“,”的3GL来实现呢。这实际上是一个非常困难的问题,所以我很难想象它可以通过数据库查询来完成。网上有很多关于这个主题的文献和一些在线计算器

编辑:

您的APL代码只是创建一个排列矩阵。例如,如果输入以下内容:

pmat2←{{,[⍳2]↑(⊂⊂⎕io,1+⍵)⌷¨⍒¨↓∘.=⍨⍳1+1↓⍴⍵}⍣⍵⍉⍪⍬}
pmat2 3
您可以得到以下矩阵:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
根据维基百科:

循环赛(或全场比赛)是“每个参赛者依次会见所有其他参赛者”的比赛

根据Markus Triska在其关于该主题的硕士论文中所述:

社交高尔夫问题(SGP)是一个组合优化问题。这项任务是安排g×p高尔夫球手在g组的p名球员中进行w周的比赛,这样就不会有两名球员在同一组中比赛超过一次

从数学上讲,这是一个很大的区别。循环赛是两人一组的比赛,所以如果你有9名选手,就需要在8轮中进行36场比赛。使用社交高尔夫球手,您可以将他们分成三组,需要在4轮中进行12场比赛:

6 4 8   1 8 3   1 9 6   9 5 8
3 9 7   4 2 9   4 3 5   4 7 1
5 1 2   5 7 6   8 7 2   6 3 2

我不知道这是否有效,但你可以制作一个表,用带有where子句的交叉连接将个人表(只有id就足够)插入8次,在第二个连接中排除employee.id(第二列)!=employee.id(第一列)。在第三个交叉连接中,u必须为employee.id(第三列)!=employee.id(第二列)


在我看来,这将产生所有的组合。然后你只需要随机选择一个并保存它,这样你就不会再选择它了。

在SQL中,答案其实很简单,它需要两个表,一个表定义员工,另一个表定义席位。例如:

表:雇员

栏目:

EmployeeID-这必须是唯一标识符。 雇员姓名 活动员工-(是/否) 等等

表:座位

栏目:

SeatID-这必须是唯一标识符。 表号 表序号 等等

现在定义一个没有连接条件的查询,称为笛卡尔积,这通常是一个不希望出现的结果,但在本例和一些数据仓库实现中不是这样

Select EmployeeID, SeatID from Employees, Seating where ActiveEmployee = 'Y' order by TableSeatNumber, TableNumber;
这将为您提供每个座位的每个员工的结果。这种方法首先在不同的桌子上为整个人群提供不同的座位。如果您的员工流动率很高,则将结果与历史记录进行比较,然后从笛卡尔积中否定该实例

如果您想更多地混合座位,可以使用排序顺序的其他选项,例如唯一字段


希望这能有所帮助。

解决问题 如果问题是安排会议的真正任务,那么在提出问题时会出现一些错误。
这是因为工人的数量,甚至可用的桌子和座位的数量并不是一个基本的物理常数:

  • 有人可能被解雇,无法参加下次会议
  • 人力资源部为新项目又雇佣了10名员工,所有员工都必须参加下一次会议
  • 下周开始装修餐厅,下个月只有20张桌子可用
所以问题听起来是这样的:“我们需要在接下来的5-10个工作日安排会议,让尽可能多的人与之前没有交谈过的人会面,让尽可能少的人与另一个人交谈两次。”
with params as (
  select
    320 n,  -- number of persons
    8   k,  -- number of seats per table
    41  p   -- least prime which greather or equal n/k  
  from dual
),
person_set as (
  select level person_id from dual connect by level <= (select n from params)  
), 
person_map as (
  select 
    person_id,
    mod( mod(person_id, p.k * p.p), p.k )    x,
    trunc( mod(person_id, p.k * p.p) / p.k ) y
  from person_set, params p
),
meetings as (
  select (level-1) meeting_no 
  from dual 
  connect by level <= (select least(k*p, (n-1)/(k-1)) from params)
),
seats as (
  select (level-1) seat_no 
  from dual 
  connect by level <= (select k from params)
),  
tables as (
  select (level-1) table_no 
  from dual 
  connect by level <= (select p from params)
),
meeting_plan as (
  select --+ ordered use_nl(seats tables)
    meeting_no,
    seat_no,
    table_no, 
    (  
       select 
         person_id 
       from 
         person_map 
       where 
         x = seat_no 
         and 
         y = mod(meeting_no*seat_no + table_no, p.p)
    ) person_id
  from 
    meetings, seats, tables, params p
)
select 
  meeting_no,
  table_no,
  max(case when seat_no = 0 then person_id else null end) seat1,
  max(case when seat_no = 1 then person_id else null end) seat2,
  max(case when seat_no = 2 then person_id else null end) seat3,
  max(case when seat_no = 3 then person_id else null end) seat4,
  max(case when seat_no = 4 then person_id else null end) seat5,
  max(case when seat_no = 5 then person_id else null end) seat6,
  max(case when seat_no = 6 then person_id else null end) seat7,
  max(case when seat_no = 7 then person_id else null end) seat8
from meeting_plan
group by meeting_no, table_no
order by meeting_no, table_no
-- List of persons
create table person(
  person_id number not null -- Unique person identifier.
);
-- primary key
alter table person add constraint pk_person primary key (person_id) using index;

-- List of all possible unique person pairs
create table person_pair(
  person1_id number not null, -- 1st person from pair, refers person table. 
  person2_id number not null, -- 2nd person from pair, refers person table.
                              -- person1_id always less than person2_id.
  meet_count number           -- how many times persons in pair meet each other.
);
-- primary key
alter table person_pair add constraint pk_person_pair primary key (person1_id, person2_id) using index;
-- indexes for search
alter table person_pair add constraint idx_pair2 unique (person2_id, person1_id) using index;

-- Placement information for meetings
create table meeting(
  meeting_number number not null, -- sequential meeting number
  table_number   number not null, -- table number
  person_id      number not null, -- person placed on that table and meeting
  seat_no        number           -- seat number
);
-- primary key: person can seat on the same table only once in one meeting
alter table meeting add constraint pk_meeting primary key (meeting_number, table_number, person_id) using index;
-- disallow duplicate seats on the same table during one meeting
alter table meeting add constraint miting_unique_seat unique (meeting_number, table_number, seat_no) using index;
-- person can participate in meeting only once
alter table meeting add constraint miting_unique_person unique (meeting_number, person_id) using index;
begin
  -- Fill persons list with initial data 
  insert into person(person_id)
  select level from dual connect by level <=20;

  -- generate person pairs
  insert into 
    person_pair(person1_id, person2_id, meet_count)
  select 
    p1.person_id, 
    p2.person_id, 
    0
  from 
    person p1,
    person p2
  where 
    p1.person_id < p2.person_id
  ;

end;
/
select * from person order by person_id
/
select * from person_pair order by person1_id, person2_id
/
declare 
  vMeetingNumber      number;      -- number of current meeting 
  vNotMeetPairCount   number;      -- number of pairs not meet before 
  vTableCapacity      number := 4; -- number of places at one table
  vTableCount         number;      -- number of tables    
begin

  -- get next meeting number for case of continous generation
  select nvl(max(meeting_number),0) + 1 into vMeetingNumber from meeting;

  -- count minimum required table number
  select ceil(count(1)/vTableCapacity) into vTableCount from person;

  -- number of remaining pairs who don't meet before
  select count(1) into vNotMeetPairCount 
  from person_pair 
  where meet_count < 1;

  -- Generate new meetings while not all persons meet each other
  while (vNotMeetPairCount > 0) loop

    -- select list of persons to place
    for cPersons in (

      with person_meets as (
        select  
          pp.person1_id, pp.person2_id, pp.meet_count,
          ( row_number() over (
              order by pp.meet_count desc, pp.person1_id 
            )
          )   row_priority
        from 
          person_pair pp    
     )
     select person_id from (
       select person_id, sum(pair_meet_count*pair_meet_count) pair_meetings from (
         select person1_id person_id, meet_count pair_meet_count from person_meets
         union all
         select person2_id person_id, meet_count pair_meet_count from person_meets
       )
       group by person_id   
     )  
     order by pair_meetings desc

    ) loop

      -- add current person to most applicable table

      insert into meeting(meeting_number, table_number, person_id, seat_no)
      select 
        vMeetingNumber, table_number, cPersons.person_id, seat_no
      from (
        with available_tables as (
          select 
            table_number, places_occupied
          from (  
            select
              t.table_number,
              (
                select count(1)
                from meeting m
                where 
                  m.meeting_number = vMeetingNumber 
                  and     
                  m.table_number = t.table_number
              ) places_occupied
            from (
              select level table_number
              from dual connect by level <= vTableCount
            ) t
          )
          where places_occupied < vTableCapacity    
        )
        select 
          table_number,
          seat_no,
          ( row_number() over ( order by 
              -attractor_factor*attractor_factor - decode(attractor_factor,0,0,repellent_factor/2) + repellent_factor 
            ) 
          )  row_priority
        from (     
            select                             
              t.table_number,
              t.places_occupied + 1 seat_no,
              (
                select 
                  count(1)
                from
                  meeting     m,
                  person_pair pp
                where
                  m.table_number = t.table_number
                  and
                  m.meeting_number = vMeetingNumber
                  and
                  pp.person1_id = least(m.person_id, cPersons.person_id)
                  and               
                  pp.person2_id = greatest(m.person_id, cPersons.person_id)
                  and
                  pp.meet_count = 0
              )  attractor_factor,
              (
                select 
                  nvl(sum(meet_count),0)
                from
                  meeting     m,
                  person_pair pp
                where
                  m.table_number = t.table_number
                  and
                  m.meeting_number = vMeetingNumber
                  and
                  pp.person1_id = least(m.person_id, cPersons.person_id)
                  and               
                  pp.person2_id = greatest(m.person_id, cPersons.person_id)
                  and
                  pp.meet_count > 0
              )  repellent_factor,
              1 random_factor --trunc(dbms_random.value(0,1000000)) random_factor
            from              
              available_tables t
        )
      )
      where 
        row_priority = 1
      ;  

    end loop;

    -- Update number of meets 
    update person_pair 
    set meet_count = meet_count + 1 
    where         
      (person1_id, person2_id) in (
        select 
          m1.person_id person1_id,
          m2.person_id person2_id
        from
          meeting m1,
          meeting m2
        where   
          m1.meeting_number = vMeetingNumber
          and
          m2.meeting_number = vMeetingNumber
          and
          m1.table_number = m2.table_number  
          and 
          m1.person_id < m2.person_id
      )
    ;

    -- advice to next meeting
    vMeetingNumber := vMeetingNumber + 1;

    -- count pairs who don't meet before
    select count(1) into vNotMeetPairCount 
    from person_pair
    where meet_count < 1;

  end loop;

end;