两组不同规模的成员必须相互见面(1v1,一次)

时间:2016-08-28 07:50:04

标签: javascript jquery algorithm

我最近一直在努力写一种快速约会风格"算法。基本目标是让一个小组中的每个成员(男性)在他们的桌子上与其他小组(女性)的每个成员会面一次。

条件是:

  1. 表格数量等于女性人数。
  2. 每个男人被分配到一张女人坐着的桌子上(1v1对话)。
  3. 在下一轮比赛中,每个人都会换到另一张他之前没去过的桌子。
  4. 如果组的大小不同,则任何成员(男性或女性)必须连续两轮暂停(缺少合作伙伴)。
  5. 当男性组的成员多于女性组时会出现困难,反之亦然。

    示例:

    var men = [
          'm1', 'm2', 'm3', 'm4', 'm5',
       ],
    
       women = [
          'w1', 'w2', 'w3'
       ];
    
    
    ┃ ROUND 1                       ┃ ROUND 2
    ┌─────────────┬─────────────┐   ┌─────────────┬─────────────┐
    │     men     │    women    │   │     men     │    women    │
    ├─────────────┴─────────────┤   ├─────────────┴─────────────┤
    │      m1    >>>    w1      │   │      m4    >>>    w1      │
    │      m2    >>>    w2      │   │      m5    >>>    w2      │
    │      m3    >>>    w3      │   │      m1    >>>    w3      │
    │      m4          pause    │   │      m2          pause    │
    │      m5          pause    │   │      m3          pause    │
    └───────────────────────────┘   └───────────────────────────┘
    
    ┃ ROUND 3
    ┌─────────────┬─────────────┐
    │     men     │    women    │
    ├─────────────┴─────────────┤
    │      m2    >>>    w1      │
    │      m3    >>>    w2      │
    │      m4    >>>    w3      │
    │      m5          pause    │
    │      m1          pause    │
    └───────────────────────────┘
    

    因此比赛是:

    var results = [
        'm1' = [
            'w1', 'w3', null
        ],
    
        'm2' = [
            'w2', null, 'w1'
        ],
    
        'm3' = [
            'w3', null, 'w2'
        ],
    
        'm4' = [
            null, 'w1', 'w3'
        ],
    
        'm5' = [
            null, 'w2', null
        ],
    ];
    

    到目前为止,尽管在本网站及其他网站上查看了类似的问题,但我在解决此问题方面的尝试仍然没有成功(见下面的截图)。在这次尝试中,我进行了15/15轮比赛,最后还是暂停了两轮或更多轮的人等等。

    enter image description here *截图中的名称是假的;由Faker生成

    我在Javascript中的当前(非工作)尝试

    我基本上有四个数组

    1. 男人阵容
    2. 女性阵容
    3. 回合的可用表格数组
    4. 每个男人未满足的女性人数
    5. 
      
      var men_array                     = [
        'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 'm7', 'm8', 'm9', 'm10'
      ];
      
      var women_array                   = [
        'w1', 'w2', 'w3', 'w4', 'w5'
      ];
      
      var available_tables_this_round   = [];
      var unmet_women                   = [];
      
      // Run round
      function start_round(){
      	console.log('START OF ROUND ----------------');
      
          // Set available tables this round
          // One table per woman
          available_tables_this_round = women_array;
        
          // Selected table
          var selected_table;
        
          // Finding table partner for each man
          men_array.forEach(function(item){
              var current_man = item;
              
              // Checking if this user has unmet women on record
              if(typeof unmet_women[current_man] == 'undefined'){
                  // Unmet women array not set. Setting...
                  unmet_women[current_man] = women_array;
              }
            
              // Loop through available tables to see which
              // of those the man can join (has not visited yet).
              for(var i = 0; i < available_tables_this_round.length; i++){
      						var current_woman = available_tables_this_round[i];
                  
                  // If woman among the available has not been met
                  if($.inArray(current_woman, available_tables_this_round) !== -1){
                    	selected_table = current_woman;
                      
                       // Removing table from those available this round
                       available_tables_this_round = $.grep(available_tables_this_round, function(value) {
                        return value != selected_table;  
                      });
                    
                      // Removing woman from unmet by this man
                      unmet_women[current_man] = $.grep(unmet_women[current_man], function(value) {
                        return value != selected_table;   
                      });
                      
                      console.log(current_man, '>>>', selected_table);
                    
                    	// Exiting loop since we've found a match for the man (for this round!)
                      break;
                  }
              }        
          });
          
          console.log('END OF ROUND ----------------');
        
          
      }
      
      // Button handling
      $(document).on('click', 'button#start_round_btn', start_round);
      &#13;
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <button id="start_round_btn">Start Round</button>
      &#13;
      &#13;
      &#13;

4 个答案:

答案 0 :(得分:4)

您可以暂停填充数组,并首先保持数组的长度相同。然后你可以使用数组的叉积,在第一个数组上移位,并保留第二个数组的值。

function getSeating(a1, a2) {
    function fill(a, l) {
        var p = l - a.length;
        a = a.slice();
        while (p) {
            a.splice(p, 0, 'pause' + p);
            p--;
        }
        return a;
    }

    var max = Math.max(a2.length, a1.length);

    a1 = fill(a1, max);
    a2 = fill(a2, max);
    return a1.map(function (_, i) {
        return a2.map(function (b, j) {
            return [a1[(i + j) % max], b];
        });
    });
}

console.log(getSeating(['m1', 'm2', 'm3', 'm4', 'm5'], ['w1', 'w2', 'w3']));
console.log(getSeating(['m1', 'm2', 'm3'], ['w1', 'w2', 'w3', 'w4', 'w5']));
console.log(getSeating(['m1', 'm2', 'm3', 'm4', 'm5'], ['w1', 'w2', 'w3', 'w4', 'w5']));

console.log(getSeating(['m1', 'm2', 'm3', 'm4'], ['w1', 'w2']));
console.log(getSeating(['m1', 'm2'], ['w1', 'w2', 'w3', 'w4']));
console.log(getSeating(['m1', 'm2', 'm3', 'm4'], ['w1', 'w2', 'w3', 'w4']));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:4)

这里的主要问题是确保男性和女性都不会连续两次停顿。

为了确保不会发生这种情况,请考虑放置&#34;暂停表&#34;在与女性的桌子之间,直到你有足够的桌子来安排男人。这意味着在基于0的表编号中,这些&#34;暂停表&#34;得到一个奇怪的位置指数。

当你把男人从一张桌子循环到下一张桌子时,永远不会有男人穿上&#34;暂停&#34;连续两次,但他们会遇到每个女人,然后再回到他们第一次被分配到的桌子上。

使用这种方法,当男性比女性多两倍时,问题也很明显。在这种情况下,一个人按顺序暂停两次是不可避免的。

当男性较少时,可以使用类似的技巧:女性可能永远不会单独按顺序进行一轮以上,因此在这种情况下,使用相同的方法引入假人(&#34;暂停座位&#34;) :把这些男人排成一排,并在这一行中注入这些假人&#34;所以他们最终得到奇怪的指数。我将这个可能延长的行称为“#34;座位”。

如果你这样做,你将拥有与桌子一样多的座位,并且为每一轮产生分配变得微不足道:只需将座位在桌子上循环:每一轮座位移动到下一轮按顺序排列表,循环回到最后一个表后的第一个表。

以下是代码:

&#13;
&#13;
function getRounds(men, women) {
    // Exclude the cases where a solution is not possible
    if (men.length > women.length * 2) throw "not possible: too many men"; 
    if (women.length > men.length * 2) throw "not possible: too many women"; 
    // Create the tables:
    // Women get a fixed place, so the table name is the woman's name
    var tables = women.slice();
    // Create the seaters: they are the men
    var seaters = men.slice();
    // Which do we have fewer of? tables or seaters?
    var maxLen = Math.max(tables.length, seaters.length);
    var least = tables.length < maxLen ? tables : seaters;
    // The smallest of both arrays should get some dummies added to it.
    // We insert the dummies at odd indices: This is the main point of this algorithm
    for (var i = 0; least.length < maxLen; i++) least.splice(i*2+1, 0, 'pause');

    // Now everything is ready to produce the rounds. There are just as many
    // rounds as there are tables (including the "pause tables"):
    return tables.map( (_, round) =>    
        // Assign the men: each round shifted one place to the left (cycling):
        tables.map( (table, tid) => [seaters[(round+tid)%maxLen], table] )
    );
}

var result1 = getRounds(["John", "Tim", "Bob", "Alan", "Fred"], 
                        ["Lucy", "Sarah", "Helen"]);
console.log(result1);

var result2 = getRounds(["John", "Tim"],
                        ["Lucy", "Sarah", "Helen", "Joy"]);
console.log(result2);
&#13;
&#13;
&#13;

答案 2 :(得分:3)

你可以像这样创建一个数组表:

var tables = men.map((element, index) => index < women.length ? [element, women[index]] : [element, "pause"]);

获取:

[ [ 'm1', 'w1' ],
  [ 'm2', 'w2' ],
  [ 'm3', 'w3' ],
  [ 'm4', 'pause' ],
  [ 'm5', 'pause' ] 
]

因此,你只需重组夫妻“新生儿”即可。

答案 3 :(得分:1)

好的我喜欢这个问题。我的方法将处理,直到一个组的大小是另一组的两倍。没有人会连续两次等待。我也很高兴有机会使用我的Array.prototype.rotate()方法。

好的代码是;

Array.prototype.rotate = function(n){
	var len = this.length,
	    res = new Array(this.length);
	if (n % len === 0) return this.slice(); // no need to rotate just return a copy
	else for (var i = 0; i < len; i++) res[i] = this[(i + (len + n % len)) % len];
	return res;
};

function arrangeTables(matches){
  var meetings = [],
    tableCount = matches[0].length;
  for (var i = 0, len = matches.length; i < len; i++){
    meetings.push(matches.slice(0,tableCount).map((t,ix) => t[ix]));
    matches = matches.concat(matches.splice(0,tableCount).rotate(1));
  }
  return meetings;
}

var men = ['m1', 'm2', 'm3', 'm4', 'm5'],
  women = ['w1', 'w2', 'w3'],
    few = [],
   much = men.length > women.length ? (few = women,men) : (few = men,women), // this is needed for the nesting order of maps to get matches.
matches = much.map(m => few.map(f => [f,m]));
 result = arrangeTables(matches);
console.log(result);

我们每轮都有很多性别表,我们必须做出与性别数量相当多的轮次。

首先我们找到所有可能的匹配

matches = much.map(m => few.map(f => [f,m]))

返回我们

[ [ [ 'w1', 'm1' ], [ 'w2', 'm1' ], [ 'w3', 'm1' ] ],
  [ [ 'w1', 'm2' ], [ 'w2', 'm2' ], [ 'w3', 'm2' ] ],
  [ [ 'w1', 'm3' ], [ 'w2', 'm3' ], [ 'w3', 'm3' ] ],
  [ [ 'w1', 'm4' ], [ 'w2', 'm4' ], [ 'w3', 'm4' ] ],
  [ [ 'w1', 'm5' ], [ 'w2', 'm5' ], [ 'w3', 'm5' ] ] ]

然后我们转到我们的arrangeTables()函数。它像这样工作

  1. 将第一张表格排成多行(本例中为3行)并选择3个会议 根据行索引并将它们放在一个数组中。

    meetings.push(matches.slice(0,tableCount).map((t,ix) => t[ix]));

    因此在第一个中选择了[["w1","m1"],["w2","m2"],["w3","m3"]] 轮。

  2. 删除matches的前三行。旋转删除的行 一次并将它们连接回matches

    matches = matches.concat(matches.splice(0,tableCount).rotate(1));

    所以第二轮比赛将如下所示。

    [ [ [ 'w1', 'm4' ], [ 'w2', 'm4' ], [ 'w3', 'm4' ] ],
      [ [ 'w1', 'm5' ], [ 'w2', 'm5' ], [ 'w3', 'm5' ] ],
      [ [ 'w1', 'm2' ], [ 'w2', 'm2' ], [ 'w3', 'm2' ] ],
      [ [ 'w1', 'm3' ], [ 'w2', 'm3' ], [ 'w3', 'm3' ] ],
      [ [ 'w1', 'm1' ], [ 'w2', 'm1' ], [ 'w3', 'm1' ] ] ]
    
  3. 多次重复此例行程序“超出性别数”。 (在这种情况下为5)