最近遇到一个演唱会随机选座的问题,这个问题细想起来确实有趣,正好周末有空,所以我想花点时间分享一下我的解题思路。
演唱会会场分A、B、C、D四个区域,每个区域第一排50个座位,向后每排递增2个座位,最后一排100个座位。一个人可以买1~5张票,系统要随机分配座位,但必须连号,问要怎么分配?
因为买票的张数不确定性,如果直接随机分配,则有可能出现很多单个位置空出的情况,降低了座位的有效利用率。如果直接顺序出票,那就出现人群扎堆的情况。所以我们要在均衡分布与高利用率之间取一个平衡点。
首先定义座位信息
1 2 3 4 5 6 7 8 9 let item = { index: 0, //下标(索引) group: 0, //分组 groupName: 'A', //分组名称 number: 3, //座位编号 row: 9, //第几排 disable:false //该座位是否可选 };
把座位和排数用数组保存起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 let front = 2; //前排座位数 let back = 10; //后排座位数 let .gap = 2; //每行座位数差 let group = 4; //分组数 let lines = (this.back - this.front) / this.gap; //每个分组有多少排 let index = 0; //下标(索引) for (let g = 0; g < this.group; g++) { for (let line = this.lines; line >= 0; line--) { let rowArray = []; for (let seat = 0; seat < (this.back - this.gap * (this.lines - line)); seat++) { let item = { index:index++, group: g, groupName: this.groupName(g), //分组名称 number: seat, row: line, disable:false }; rowArray.push(item); seats.push(item); //console.log(item) } rows.push(rowArray); }; }
把符合条件的座位排数筛选出来(即有足够连号的空位的排数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 suitableRows(length) {//length为买票的张数 let haveSeatRows = []; this.rows.forEach((list) => { //可选的座位数组 let haveSeatList = list.filter((item) => { return !item.disable; }); if(haveSeatList.length <= 0) return false; //有N张连号的排数 if(this.selectPlace(haveSeatList,length).length > 0) { haveSeatRows.push(haveSeatList); } }); if(haveSeatRows.length > 0) { return haveSeatRows; }else{ return false; } }
最后把从筛选出来的排数中选出座位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 let index = Math.floor(Math.random() * haveSeats.length); let places = this.selectPlace(haveSeats[index], length); selectPlace(list, length) { let places = []; for(let i = 0;i < list.length - 1;i++) { let end = i + length; if(end > list.length) break; let selects = list.slice(i, end); let flag = false; selects.forEach((val, k) => { if(k + 1 <= selects.length - 1) { if(val.number + 1 == selects[k + 1].number) { flag = true; }else{ flag = false; } } }); if(flag) { places = selects; break; } } return places; }
总结起来,基本思路就是把符合条件的行数收集起来,再从所有行数中随机选出一行,顺序出票,从而在均衡分布与高利用率之间取一个平衡点。
demon实例,点击查看!