一、题目:公司有n个组,>=5,每组人数相同,>=2人,需要进行随机的组队吃饭。
二、要求
- 两两一队或三人一队,不能落单
- 两人队、三人队各自的队伍数均不得少于2
- 一个人只出现一次
- 队伍中所有人不能来自相同组
- 随机组队,重复执行程序得到的结果不一样,总队伍数也不能一样
- 注释注释注释
注:要同时满足条件1-6,
举例
小组列表
var GroupList = [
['小名', '小红', '小马', '小丽', '小强'],
['大壮', '大力', '大1', '大2', '大3'],
['阿花', '阿朵', '阿蓝', '阿紫', '阿红'],
['A', 'B', 'C', 'D', 'E'],
['一', '二', '三', '四', '五'],
['建国', '建党', '建民', '建超', '建跃'],
['爱民', '爱军', '爱国', '爱辉', '爱月']
]
输入:GroupList
示例输出:
小强 大3] [阿红 E] [五 建跃] [爱月 小名] [大壮 阿花] [A 一] [建国 爱民] [小红 大力] [阿朵 B] [二 建党] [爱军 小马] [大1 阿蓝] [C 三] [建民 爱国 小丽] [大2 阿紫 D] [四 建超 爱辉]
三、解决思路
总共6个条件,其中一个是注释
- 第一个条件是只能是两个或者三个一组,可以先随机生成2个一组的队伍,和三个一组的队伍,但是可能会出现最后一个队伍是一个人,此时需要把这个人加入到2个人一组的队伍中(ps:因为同组人不可以一个队伍,所以需要判断是否有在一组的人在这个队伍)
- 两人队、三人队各自的队伍数均不得少于2,所以生成结束后可以判断,或者提前生成队伍,看看队伍是否符合不少于2。这里还需要判断是否落单,因为落单的时候需要加入2人的队伍,所以两人队伍会变成3人队伍。
- 一个人只出现一次,需要标记是否已经使用
- 队伍中所有人不能来自相同组,这里需要判是否为同一组
- 随机组队,重复执行程序得到的结果不一样,总队伍数也不能一样,这里组队就必须用随机,不能hard code
四、代码实现
todo
那个地方,我觉得基本不可能出现,2,3 人队伍数量小于二,但是随机就有可能,所以可以提前把队伍数随机出来,如果出现,就重新随机一次
func main() {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
groupList := [][]string{
{"小名", "小红", "小马", "小丽", "小强"},
{"大壮", "大力", "大1", "大2", "大3"},
{"阿花", "阿朵", "阿蓝", "阿紫", "阿红"},
{"A", "B", "C", "D", "E"},
{"一", "二", "三", "四", "五"},
{"建国", "建党", "建民", "建超", "建跃"},
{"爱民", "爱军", "爱国", "爱辉", "爱月"},
}
// 计算总人数和每组人数
numGroups := len(groupList)
numPeoplePerGroup := len(groupList[0])
totalPeople := numGroups * numPeoplePerGroup
// 初始化结果数组
result := make([][]string, totalPeople/2)
// 初始化标记数组
var usedGroups = make([][]bool, 0, 10)
for i := 0; i < numGroups; i++ {
usedGroups = append(usedGroups, make([]bool, numPeoplePerGroup))
}
counter := 0
var groupIndex = 0 //记录最后一个最的索引
// 随机分组
for i := 0; i < len(result); i++ {
var team []string
// todo 随机选取2人或3人组队 这里可以把所有的随机先随机出来,然后判断是否2、3 都大于两个
numPeople := r.Intn(2) + 2
for len(team) < numPeople && counter < totalPeople {
// 随机选取一个小组
//for groupIndex := 0; groupIndex < numGroups; groupIndex++ {
groupIndex = r.Intn(numGroups)
// 从该小组中随机选取一个人
personIndex := r.Intn(numPeoplePerGroup)
// 如果该小组已被使用过,则跳过
if usedGroups[groupIndex][personIndex] {
continue
}
person := groupList[groupIndex][personIndex]
// 检查是否与已选队员来自同一小组
if sliceContains(groupList[groupIndex], team) {
continue
}
// 将该人加入队伍
team = append(team, person)
counter++
// 标记该小组已使用
usedGroups[groupIndex][personIndex] = true
//}
}
// 将队伍加入结果数组
result[i] = team
}
//删除最后为nil 的结果
for len(result[len(result)-1]) == 0 {
result = result[:len(result)-1]
}
//最后等于1,需要合并到两的队伍里面
if len(result[len(result)-1]) == 1 {
temp := result[len(result)-1]
result = result[:len(result)-1]
for i := range result {
if len(result[i]) == 2 {
// 检查是否与已选队员来自同一小组
if sliceContains(groupList[groupIndex], result[i]) {
continue
}
result[i] = append(result[i], temp...)
break
}
}
}
// 输出结果
var total int
for _, team := range result {
if len(team) > 0 {
fmt.Println(team)
total = +total + len(team)
}
}
fmt.Println(total)
return
}
func sliceContains(slice []string, target []string) bool {
for _, value := range target {
if contains(slice, value) {
return true
}
}
return false
}
func contains(slice []string, target string) bool {
for _, value := range slice {
if value == target {
return true
}
}
return false
}
五、拓展
如果好的算法希望大家补充呀,期待大家提出宝贵意见