2013-07-24 31 views
8

Thử thách này là một tình huống Social Golfer Problem. Tôi có một công ty với 320 người. Gần đây tôi đã triển khai chương trình Quản lý theo mục tiêu (MBO), nơi mỗi công nhân được chỉ định các mục tiêu sẽ được hoàn thành hàng tháng. Một trong những mục tiêu định kỳ là đến đúng giờ tại nơi làm việc để tham dự một cuộc họp cà phê và dounut 30 phút mỗi buổi sáng. Cuộc họp được tổ chức tại phòng ăn của chúng tôi với 50 bàn. Mỗi bàn có thể chứa tối đa 8 người. Cộng hoặc trừ 80 chỗ trống mỗi ngày làm việc, vì hiện tại có công suất tối đa 400. Tôi muốn tạo bố trí chỗ ngồi vòng tròn sao cho mỗi người có thể gặp gỡ và cộng tác với mọi người khác trên cơ sở luân phiên.Làm cách nào để tạo ma trận "Xã hội Golfer" cho sắp xếp chỗ ngồi của nhân viên?

(CHỈNH SỬA) Quy tắc: Cần có 8 bộ duy nhất cho mỗi ngày làm việc. Một người không thể ngồi lại được với những người khác mà họ đã ngồi trong quá khứ cho đến khi tất cả các hoán vị có thể đã cạn kiệt.

EDIT: Một ví dụ về kết quả mong muốn là:

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: 
. 
. 
... 
. 

Không ai trong số các con số công nhân (phần tử) có thể lặp lại trong mỗi bộ (mảng) của 8 công nhân cho đến khi tất cả các bộ độc đáo càng tốt (hoán vị) đã cạn kiệt. Sau đó, chu trình bắt đầu lại từ đầu, có lẽ là thay đổi các yếu tố, chỉ sau đó, một công nhân sẽ ngồi với một công nhân khác mà họ đã gặp trước đó. Sau đó tôi muốn gửi email cho mỗi nhân viên về bảng mà họ đã được chỉ định để ngồi vào ngày làm việc tiếp theo. Mỗi công nhân sẽ không biết ai khác là sittibg tại bàn được chỉ định của họ cho đến khi họ đến bàn. Chỉ có tôi sẽ có danh sách hoàn chỉnh cho việc sắp xếp chỗ ngồi. (Đó là một trò chơi "Ghế Nhạc")

Đây không phải là một đoạn trích hoặc bài tập ở trường. Một người bạn sử dụng ngôn ngữ lập trình APL đã nói với tôi rằng cô ấy có thể tạo ra các kết quả mong muốn với một dòng mã, nhưng chúng tôi chỉ sử dụng DBMS dựa trên SQL (IBM Informix 11.70 và Oracle 11).

Vì vậy, tôi có một bảng SQL với các cột sau:

employee.id  INT  {unique primary key} 
employee.FullName VARCHAR 
... 

Sau đây một dòng mã lập trình APL tạo hoán vị ma trận:

pmat2←{{,[⍳2]↑(⊂⊂⎕io,1+⍵)⌷¨⍒¨↓∘.=⍨⍳1+1↓⍴⍵}⍣⍵⍉⍪⍬} 

Trong SQL, tôi có thể tạo ra kết quả mong muốn với một câu lệnh SELECT, tôi có cần nhiều câu lệnh SELECT INTO TEMP hay là một thủ tục được lưu trữ cần thiết để có được kết quả mong muốn?

Câu lệnh SELECT/s hoặc SP của tôi trông như thế nào?

EDIT: Nếu kết quả mong muốn không khả thi với SQL, nó có thể được thực hiện bằng 3GL như C# không?

+0

DBMS nào? Trong MSSQL, nó có thể thực hiện được với một đệ quy CTE – Jaloopa

+0

Xin lỗi, Microsoft Access và IBM Informix. Tôi sẽ chỉnh sửa câu hỏi của mình để bao gồm DBMS. –

+0

@Jalopy: Nó có thể được thực hiện chỉ với ANSI SQL sao cho không quan trọng DBMS nào? –

Trả lời

4

Được gọi là "Social Golfer Problem" và mặc dù nó đã được hoàn thành với APL, không phải bằng một dòng. Nó thực sự là một vấn đề rất khó khăn, vì vậy tôi có một thời gian khó tưởng tượng rằng nó có thể được thực hiện với một truy vấn cơ sở dữ liệu. Có rất nhiều tài liệu trực tuyến về chủ đề và một số máy tính trực tuyến.

EDIT:

đang APL của bạn chỉ đơn giản là tạo ra một ma trận hoán vị.Ví dụ, nếu bạn nhập như sau:

pmat2←{{,[⍳2]↑(⊂⊂⎕io,1+⍵)⌷¨⍒¨↓∘.=⍨⍳1+1↓⍴⍵}⍣⍵⍉⍪⍬} 
pmat2 3 

Bạn nhận được các ma trận sau:

1 2 3 
1 3 2 
2 1 3 
2 3 1 
3 1 2 
3 2 1 

Theo Wikipedia:

Một giải đấu round-robin (hoặc tất cả-play giải đấu) là một cuộc thi "trong đó mỗi thí sinh sẽ gặp tất cả các thí sinh khác lần lượt".

Theo Markus Triska trong luận án thạc sĩ của ông về đề tài này:

Các xã hội Golfer Vấn đề (SGP) là một bài toán tối ưu tổ hợp. Nhiệm vụ là lập kế hoạch cho các gôn thủ g × p trong các nhóm người chơi p trong vòng w tuần mà không có hai người chơi golf nào trong cùng một nhóm nhiều hơn một lần.

Về mặt toán học có sự khác biệt lớn. Một giải đấu round-robin liên quan đến các nhóm của hai, vì vậy nếu bạn có 9 thí sinh, nó sẽ yêu cầu 36 trận đấu trong 8 vòng. Với các tay golf xã hội, bạn có thể nhóm chúng bằng cách threes, và nó sẽ đòi hỏi 12 trận trong 4 vòng:

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 
+0

Vì vậy, trong toán học, vấn đề của tôi sẽ giống như 8! 320 (320 giai thừa 8 tại một thời điểm)? Tôi có 50 bàn ăn. Mỗi bàn có 8 người. Điều này có nghĩa là 80 chỗ trống. Bạn tôi nói APL có ma trận xoay và đảo ngược [chức năng APL] (http://en.wikipedia.org/wiki/APL_syntax_and_symbols), khi kết hợp với 8! 320 có thể được thực hiện với một dòng mã trong một hàm nhuộm! –

+1

Đây là liên kết hiển thị các giải pháp mẫu khác nhau: http://faculty.mercer.edu/schultz_sr/social_golfer/social_golfer.html. Xem cách trình bày của bạn về vấn đề ngăn xếp với những ví dụ đó.Ngoài ra, hãy kiểm tra các liên kết tôi cung cấp trong câu trả lời của tôi cho thấy làm thế nào các vấn đề golfer xã hội có thể được giải quyết với APL. –

+0

Mục tiêu của tôi là để mỗi người gặp gỡ tất cả những người khác tại một bàn có 8 người mà không gặp lại cùng một người cho đến khi không còn kết hợp độc đáo nữa, sau đó bắt đầu lại chu kỳ. Vì vậy, đây giống như một giải đấu vòng tròn, mà không giới hạn trong các nhóm của hai người, giống như một giải đấu vòng tròn tennin đơn. Đi con số! –

-2

Tôi không thực sự biết nếu làm việc này, nhưng u chỉ có thể tạo ra một bảng và chèn các bảng cá nhân (chỉ id là đủ) 8 lần với một tham gia chéo với một mệnh đề where mà loại trừ trong tham gia thứ hai mà các employee.id (cột thứ hai)! = employee.id (cột đầu tiên). Trong thập tự giá thứ ba tham gia u sẽ phải employee.id (cột thứ ba)! = Employee.id (cột thứ hai) .....

Trong tâm trí của tôi sẽ tạo ra tất cả các kết hợp. Sau đó, u chỉ cần chọn ngẫu nhiên một và lưu nó, do đó, u không chọn nó một lần nữa.

+0

Ý tưởng của bạn sẽ không tạo ra kết quả mong muốn. Những gì tôi cần là mỗi ngày làm việc, tất cả 50 bảng, mỗi bảng có sức chứa lên đến 8 người phải có những người khác nhau không ngồi với nhau trước cho đến khi mỗi người đã gặp 319 người khác trong số 320 người trong công ty. Khi một chu kỳ đầy đủ đã cạn kiệt, sau đó chúng tôi bắt đầu với một sự kết hợp khác nhau của mọi người. Mục đích của nó là tạo ra một bầu không khí gia đình và truyền cảm hứng cho sự sáng tạo và cộng tác nhiều hơn nữa! –

-2

Trong SQL câu trả lời là thực sự khá đơn giản và nó đòi hỏi 2 bảng, một bảng xác định các nhân viên và các bàn ghế khác. Chẳng hạn như:

Bảng: Nhân viên

Cột:

EmployeeID - Đây phải là định danh duy nhất. EmployeeName ActiveEmployee - (Y/N) , vv

Bảng: Chỗ ngồi

Cột:

SeatID - Đây phải là định danh duy nhất. TableNumber TableSeatNumber , vv

Bây giờ xác định một truy vấn mà chưa tham gia tiêu chí biết như là một sản phẩm Descartes, điển hình là một kết quả không mong muốn, nhưng không phải trong trường hợp này và một số triển khai kho dữ liệu.

Select EmployeeID, SeatID from Employees, Seating where ActiveEmployee = 'Y' order by TableSeatNumber, TableNumber; 

Điều này sẽ cung cấp cho bạn kết quả của mỗi nhân viên cho mỗi chỗ ngồi. Loại này tạo ra các vị trí khác nhau trước tiên ở các bảng khác nhau cho toàn bộ dân số. Nếu số lượng nhân viên của bạn có nhiều doanh thu, sau đó so sánh kết quả với lịch sử và sau đó phủ nhận trường hợp đó từ Sản phẩm Descartes.

Các tùy chọn khác cho thứ tự sắp xếp có thể được sử dụng như các trường duy nhất nếu bạn muốn trộn chỗ ngồi nhiều hơn.

Hy vọng điều này sẽ hữu ích.

+0

Đây không phải là giải pháp tối ưu; đó là một cách tiếp cận bạo lực ... bạn sẽ kết thúc với 320 * 40 hàng và tất cả mọi người sẽ có mặt tại đây một thời gian dài _very_. – Ben

+0

Tôi không chỉ định nhân viên hoạt động và kết quả truy vấn sản phẩm Descartes của bạn sẽ không cung cấp cấu hình chỗ ngồi độc đáo cho mỗi ngày làm việc. –

3

Sự cố
Nếu vấn đề là nhiệm vụ thực sự để lên lịch cuộc họp thì có một số sai lầm khi đặt câu hỏi.
Đó là bởi vì số lượng người lao động và thậm chí là một số bảng có sẵn và ghế không phải là một hằng số vật lý cơ bản:

  • ai đó có thể bị sa thải và không thể tham gia vào các cuộc họp tiếp theo;
  • Nhân sự đã thuê thêm 10 công nhân cho dự án mới và tất cả họ phải tham gia cuộc họp tiếp theo;
  • Vào tuần tới, bắt đầu cải tạo phòng ăn và chỉ có 20 bàn sẽ có sẵn cho tháng tiếp theo.

Vì vậy, vấn đề có vẻ như sau: "Chúng tôi cần lên lịch cuộc họp trong vòng 5-10 ngày làm việc theo cách sao cho càng nhiều người có thể gặp gỡ với những người mà họ không nói trước và với người thấp có thể nói chuyện với người khác hai lần và nhiều hơn nữa ".

Do đó, sự cố không phải là tạo ra tập hợp đầy đủ các hoán vị. Vấn đề là về quy hoạch tối ưu cho các cuộc họp N tiếp theo.

Lý thuyết
Sự cố có thể được phân loại là chung mathematical optimization problem. Đối với loại vấn đề đó, chúng tôi có mục tiêu tìm giải pháp tối ưu được trình bày dưới dạng bộ giá trị đối số cho (các) hàm cung cấp giá trị lớn nhất hoặc tối thiểu cho (các) hàm mục tiêu.
Để xây dựng một vấn đề chúng ta phải tìm ra gốc rễ của câu hỏi:

  • cho mỗi người phát huy tối đa một số người để đáp ứng với
  • cho mỗi cặp người giảm thiểu một số cuộc họp

Mỗi mục tiêu đó nói về các cuộc hội thoại giữa một cặp người để chúng ta phải xây dựng một vấn đề về "đáp ứng".
Biểu thị P là số người và i in [1..P]j in [1..P] làm chỉ mục người.
Biểu thị M làm số lượng cuộc họp và m in [1 .. M] làm số cuộc họp.
Sau đó, hãy giới thiệu a(i,j,m) | i < j, i in [1..P], j in [1..P], m in [1..M] như là một thực tế của cuộc họp giữa hai người trong cuộc họp cụ thể. Sau đó có thể xây dựng một hàm mục tiêu và giới hạn các điều kiện cho vấn đề.

cách tiếp cận Math
Xin lưu ý, rằng giải pháp chính xác (bất cứ ai gặp một người khác chỉ có một thời gian cho đến khi chu kỳ hoàn thành) có thể chỉ trong những trường hợp rất hiếm.
Đây là vấn đề lớp NP hoàn chỉnh và công thức phù hợp nhất là "vấn đề tối ưu hóa kết hợp hoàn hảo trong các hình ảnh siêu đồng nhất k thỏa mãn điều kiện mức độ 1 độ".
Để tìm hiểu thêm về lý thuyết, bạn có thể đặt câu hỏi tại số Mathematics hoặc kiểm tra latest works available để phân vùng siêu đồng nhất k, ví dụ: "Polynomial-time perfect matchings in dense hypergraphs"

Giải pháp phải có chính xác (P-1)/(T-1)=(320-1)/(8-1)=45.5714285714 cuộc họp vì mỗi lần gặp 7 người khác và "người khác" là 319. Vì vậy, có thể 45 cuộc họp theo các điều kiện của câu hỏi trước khi một số người gặp hai lần.

Có một câu hỏi tương tự với câu trả lời hay đã có trên StackOverflow (link). Lưu ý rằng thuật toán này để lại các vị trí trống, bởi vì cho vị trí đầy đủ của tất cả những người nó yêu cầu để seats * prime = person_count và 41 được chọn làm nguyên tố.
Dưới đây là truy vấn sử dụng giải pháp này (SQLFiddle).

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 

cách tiếp cận thực tiễn
Từ quan điểm thực tế chúng ta không cần giải pháp chính xác tối ưu với bằng chứng lý thuyết. Nếu một người gặp nhau nhiều hơn một lần thì đó không phải là vấn đề lớn, vì vậy có thể dừng lại ở giải pháp gần như tối ưu.
Giải pháp như vậy có thể được tạo ra trên cơ sở các quy tắc thực nghiệm nếu chúng ta bắt đầu đặt từng người một đến các cuộc họp và các bảng cố giữ số giao lộ cho mỗi cặp người càng thấp càng tốt.
Có nhiều chiến lược để có thể đặt và một trong số chúng được minh họa bên dưới.

Vì mục đích minh họa, tôi sử dụng Oracle vì cơ sở dữ liệu này có trong thẻ câu hỏi và có sẵn tại trang web SQLFiddle.

Ví dụ thiết lập giản đồ cơ sở dữ liệu bao gồm ba bảng:

person - bảng với danh sách của người lao động;

person_pair - bảng có danh sách tất cả các cặp công nhân độc đáo và số điểm giao nhau cho mỗi cặp, hoàn toàn là floor((P*P)/2) - floor(P/2) hàng. Trong trường hợp P = 320, nó chứa 51040 hàng.

meeting - bảng có thông tin vị trí cho từng người trong mỗi cuộc họp.

Ví dụ mã số công nhân được giới hạn ở 20 và số lượng chỗ ngồi đến 4 do giới hạn tiêu thụ tài nguyên trên trang web SQLFiddle và để giữ cho các tập dữ liệu kết quả có thể quan sát được.

Dưới đây là mã để thiết lập lược đồ và điền. Vui lòng xem qua các nhận xét để tìm hiểu thêm về các trường bảng.

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

Điền dữ liệu ban đầu (SQLFiddle):

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 
/

Tạo cuộc họp

Chiến lược bao gồm 2 phần:
1. Chọn người để cụ thể;
2. Đặt người từ danh sách từng người một vào bảng thích hợp nhất.

Sắp xếp người trong danh sách lựa chọn là cố gắng đặt những người gặp trước nhiều lần trước khi càng sớm càng tốt và đặt nó ở các bảng riêng biệt.

Việc đặt người là mục đích chính và khó khăn hơn ở giai đoạn đó là tối đa hóa số cuộc họp đầu tiên và giảm thiểu số cuộc họp lặp lại. Vì vậy, nó gần với vấn đề xây dựng các chức năng khách quan phù hợp cho vấn đề tối ưu hóa, những gì là không tầm thường trong hầu hết các trường hợp thế giới thực.

tôi chọn tiêu chí này:

Đối với mỗi bảng tính hai yếu tố: "hấp dẫn" (A) - tại sao nơi trực tiếp tại bảng đó và "thấm" (R) - tại sao người không thể ngồi trên bàn mà .
Yếu tố này bao gồm toghether để có hệ số sắp xếp bảng cuối cùng:
-A*A - (if A=0 then 0 else R/2) + R
Yếu tố "hấp dẫn" được tính là số người hiện tại không gặp trước đó.
Yếu tố "không thấm" được tính là tổng số cuộc họp của người hiện tại với tất cả những người đã có mặt tại bàn.

Rất có thể nó không tốt đến mức có thể, nhưng đủ cho các mục đích ví dụ. Ví dụ, công thức có thể được mở rộng để tính đến thời gian đã trôi qua kể từ lần họp cuối cùng.

Bạn có thể thử nghiệm với việc xây dựng biểu thức tốt để tự chọn bảng.

Tiếp theo là mã để tạo các cuộc họp.

Mã (SQLFiddle)

Một chút hơn lý thuyết

giải pháp tạo ra có thể được sử dụng như điểm khởi đầu cho một số multicriteria optimization methods, nhưng để sử dụng nó, bạn phải có một công thức chính thức tốt về vấn đề.

Hy vọng rằng tất cả các điều đã nêu ở trên sẽ giúp bạn giải quyết vấn đề.

+0

Tôi không hiểu lý do tại sao bạn sẽ đề xuất một person2 khi những gì tôi đang tìm kiếm là bộ duy nhất của 8 người ở mỗi bàn mỗi ngày làm việc. Mặc dù điều này có thể dẫn đến vài hoán vị có thể xảy ra, nhưng nó đạt được mục đích là người có thể gặp gỡ những người khác nhau mỗi ngày. Tôi không cảm thấy cách tiếp cận bạo lực là cách thích hợp để đạt được mục tiêu, có lẽ sản xuất mảng duy nhất, dịch chuyển và xoay là đúng cách? –

+0

@Frank Tôi đã thêm một số giải thích về quan điểm của tôi về xây dựng vấn đề ở đầu câu trả lời. Xin lỗi, tôi không thể hiểu ý của bạn trong khi nói về "person2". Tôi vừa giới thiệu một thực thể đại diện cho sự kiện họp giữa 2 người. Về câu hỏi về chuyển dịch và xoay tôi có thể nói rằng đó là một cách xấu vì điều kiện vấn đề có thể thay đổi theo thời gian. Hơn nữa, cách tiếp cận này không thể đảm bảo giải pháp tối ưu ngay cả với các thông số cố định - không có bằng chứng. – ThinkJet

+0

@Frank nếu bạn nghĩ về "mảng duy nhất" chỉ cần xem [trang này] (http://en.wikipedia.org/wiki/Combination) và cố gắng đếm một số 8 kết hợp từ một tập hợp 320 phần tử. .. – ThinkJet

Các vấn đề liên quan