我希望将人们分组到较小的子群组中,并且在连续会话中多次改组后,让所有人至少相遇一次。
以下是针对11人(编号0-10)和3组(3列)的此问题的答案。它需要5个会话。
Session 1: 3,6,8,10 0,1,7,9 2,4,5
Session 2: 3,5,7,8 0,1,2,10 4,6,9
Session 3: 0,1,6,8 2,3,4,9 5,7,10
Session 4: 0,3,5,9 1,4,8,10 2,6,7
Session 5: 1,3,5,6 2,8,9,10 0,4,7
Members of two groups of different size must meet each other (1v1, once)
上面的问题是类似的,但我想让人们只是在一个更大的群体中相遇,而不是一对一。
以下是我使用Alloy的方法。这适用于少数人(~15)和组(~2),但是当尺寸增加时,它会迅速导致计算时间爆炸。我需要计算~25人和~5组。
module Teaming
sig Person { groups: some Group }
sig Group { people: some Person }
sig Session { groups: some Group }
one sig Sessions { sessions: some Session }
sig GroupPerSession {}
-- Tree structures
fact {
all s: Session | s in Sessions.sessions
all g: Group | g in Session.groups
all s: Session | all p:Person | p in s.groups.people
people =~ groups
}
-- The total number of people
fact {
all s: Session | #s.groups.people = #Person
}
-- The number of groups per session
fact {
all s: Session | #s.groups = #GroupPerSession
}
-- The number of people in a group
fact {
all g: Group | (#g.people) >= div[#(Person), #(GroupPerSession)] and (#g.people) <= add[div[#Person,#GroupPerSession],1]
}
-- Mutually exclusive grouping in a session
fact separate {
all s: Session | all disj a,b: s.groups | no p: Person | p in a.people and p in b.people
}
-- Every pair of people meets somewhere
pred sameGroup {
all disj a,b: Person | some g: Group | a in g.people and b in g.people
}
-- The same people should not meet too many times
fact sameGroupNotTooMuch {
all disj a,b: Person | #{a.groups & b.groups} <= 3
}
run sameGroup for 6 Int, 5 Session, 15 Group, exactly 3 GroupPerSession, exactly 16 Person
run sameGroup for 6 Int, 6 Session, 24 Group, exactly 4 GroupPerSession, exactly 18 Person
run sameGroup for 6 Int, 7 Session, 35 Group, exactly 5 GroupPerSession, exactly 18 Person
我认为动态编程应该可行,但我找不到具体的东西。任何改进Alloy代码或其他算法的指针都会很棒。
答案 0 :(得分:2)
这是我快速解决这个问题的方法。 总的来说,实例的生成似乎更快,但在尝试将> 20个人分配到&gt; 4个组时仍然难以完成。
module Teaming
one sig Settings{
maxEncounter:Int,
minGroupSize:Int,
maxGroupSize:Int
}{
// Manually filling values there helps (1)reducing the integer bit-width needed (2) decrease the complexity (in terms of clauses)
maxEncounter=4
//minGroupSize=5
//maxGroupSize=5
minGroupSize=div[#Person, #Group]
maxGroupSize=add[minGroupSize,1]
}
sig Session{}{
Group.people[this]=Person // all person are assigned in group during a session
no disj g1,g2 :Group| g1.people[this] & g2.people [this] !=none // a person can't be in two disjoint groups of a same session
}
sig Group {
people: Session some -> some Person
}{
all s:Session| #people[s]<= Settings.maxGroupSize and #people[s]>=Settings.minGroupSize
}
sig Person {}
pred allMeet {
all disj a,b: Person | people. a & people.b != none->none
}
pred allMeetAndMinEncounter {
all disj a,b: Person | let x= (people. a & people.b) {
#x <=Settings.maxEncounter
x != none ->none
}
}
run allMeet for 6 Int, 9 Session, exactly 4 Group, exactly 20 Person
突出显示所带来的变化:
答案 1 :(得分:1)
我认为Alloy不是优化的正确工具。它是一个专注于查找反例的规范工具。然而,当然可以找到像这样的谜题的解决方案。 (我认为有一个团队开发了Alloy的扩展,最大限度地减少了找到的解决方案。)
虽然我是初学者,但我还是刺了一下。令人惊讶的是,我找到了一个解决方案,有4个会议11人和3个小组 s0 {2,9,10}, {5,6,7,8}, {0,1,3,4},
s1 {2,4,7,8}, {1,3,6,10}, {0,5,9},
s2 {1,2,3,5}, {0,7,8,10}, {4,6,9},
s3 {0,2,6}, {4,5,10}, {1,3,7,8,9}
由于Alloy不是优化器,我使用二进制方式来查找最小会话数,我发现你需要至少7个会话才能获得25/5。
这是我的完整模特:
sig P, Group {}
sig Session {
participants : Group -> P
}
fact {
// tuning goes here (max sure <= scope )
# Group = 5
# P = 25
# Session = 7
// In every session, people are divided into a constant number
// of groups.
all s : Session | s.participants.P = Group
// The sessions are continued until every pair of people
// meets each other at least once.
// Preferably, the number of times the same pair meet
// each other should be minimized.
all disj a,b : P | some participants.a & participants.b
// Everyone has to join one group in every session.
all p : P, s : Session | one s.participants.p
// The group size should be closest to (the number
// of people)/(# of groups).
// There should not be a
// groups of too few people or too many people.
all g : Group, s : Session | (# s.participants[g]) >= 3
}
run {} for 5 Group, 25 P, 24 Session, 6 int
指定这些数字的int
宽度至关重要。
找到一系列的8个会话花了5秒钟,发现7个会话耗时更长,34秒。通过增加最小值来强制更加相等的组大小仍在运行: - )
我认为该工具完全符合预期:找到 a 解决方案。找到最佳解决方案并不是那么好。