Files
hexo-blog/source/_posts/演唱会随机选座解题思路.md
T
2020-11-23 18:59:26 +08:00

3.8 KiB

title, tags, id, categories, date
title tags id categories date
演唱会随机选座解题思路
346
分享
2018-12-16 14:07:46

最近遇到一个演唱会随机选座的问题,这个问题细想起来确实有趣,正好周末有空,所以我想花点时间分享一下我的解题思路。

演唱会会场分A、B、C、D四个区域,每个区域第一排50个座位,向后每排递增2个座位,最后一排100个座位。一个人可以买1~5张票,系统要随机分配座位,但必须连号,问要怎么分配?

情景图

因为买票的张数不确定性,如果直接随机分配,则有可能出现很多单个位置空出的情况,降低了座位的有效利用率。如果直接顺序出票,那就出现人群扎堆的情况。所以我们要在均衡分布与高利用率之间取一个平衡点。

首先定义座位信息

let item = {
   index: 0,       //下标(索引)
   group: 0,       //分组
   groupName: 'A', //分组名称
   number: 3,      //座位编号
   row: 9,         //第几排
   disable:false   //该座位是否可选
};

把座位和排数用数组保存起来

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

把符合条件的座位排数筛选出来(即有足够连号的空位的排数)

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

最后把从筛选出来的排数中选出座位

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实例,点击查看!