拼图:N人坐在圆桌上。没有穿过任何其他握手的握手方式

时间:2013-08-06 09:32:26

标签: algorithm puzzle catalan

我们有n个人坐在圆桌旁。任何人都可以与任何其他人握手。这些人可以通过多少方式进行握手,这样就不会有两次握手相互交叉。

我在技术访谈论坛中找到了这个谜题,但没有答案。我能想到的一种方法是找到握手的所有排列,然后检查每个排列是否满足。

任何人都可以建议任何其他更有效的解决方案。

@edit:评论澄清:N会是偶数。

8 个答案:

答案 0 :(得分:15)

我会尝试分而治之的解决方案。如果第1个人与x人握手,它会将其余人分成两组,可以视为坐在两个圆桌旁。

答案 1 :(得分:9)

作为Python函数(Python 3.3 +),解决方案非常简单:

@lru_cache(maxsize=None) # memoize
def num_handshakes(n):
    if n % 2 == 1: return 0
    elif n == 0: return 1
    res = 0
    for i in range(0, n, 2):
        res += num_handshakes(i) * num_handshakes(n-2-i)
    return res

示例:

>>> num_handshakes(8)
14

这基本上实现了@ Buhb的分而治之的方法。另一个解决方案,一旦我们知道答案与Catalan numbers

相关
from math import factorial as fac
def catalan(n):
    return fac(2*n) // fac(n+1) // fac(n)

def num_handshakes(n):
    if n % 2 == 1: return 0
    return catalan(n//2)

答案 2 :(得分:6)

  

我会尝试分而治之的解决方案。如果第1个人与x人握手,它会将其余人分成两组,可以视为坐在两个圆桌旁。

@Buhb是对的。那种递归关系是

f(n) = sum( f(i-2) + f(n-i) for i in range(2, n))

或代码

def f(n):
    if n == 0:
        # zero people can handshake
        return 1

    if n == 1:
        # it takes two to tango
        return 0

    ways = 0

    # what if person 1 shakes with person i ?
    for i in range(2, n+1):
        # splits table into independent sets 2 .. i-1 and i+1 .. n
        ways += f(i-2) * f(n-i)

    return ways

奇数人不能握手,但f的前几个偶数值是1,2,5,14,42

搜索整数序列的百科全书,这看起来像着名的加泰罗尼亚数字http://oeis.org/A000108

序列是否真的相同,还是它们只是以相似的方式开始?他们是一样的。证实了我的数学书 - 我们的递归关系定义了加泰罗尼亚数字的f值https://en.wikipedia.org/wiki/Catalan_number#Properties

enter image description here

答案 3 :(得分:0)

什么回合?

  1. 从一次握手开始并搜索仍然可能的握手。如果不能再进行non crossing握手,请回溯。继续,直到non crossing握手不再扩展搜索树的分支。
  2. 生成的搜索树的所有顶点都是non crossing握手。
  3. 因为你的表是圆的(对称),你可以通过假设人0始终是最大握手的一部分来优化问题。

答案 4 :(得分:0)

我认为这可能是偶然n=2m.

的解决方案

从1到2米为圈内人物编号。

j, 1≤j≤m,轮人中,j与人j+1握手,所有其他握手与此“平行”(因此,j-1与j + 2,j-2与j + 3,依此类推 - 在整个过程中,标签在必要时以模数n解释。在这几轮比赛结束时,每个人都与所有人握手,只有奇数人离开。

在圆形m + j,1≤j≤m中,j与j + 2抖动,并且所有其他握手是平行的(因此j-1与j + 3,j-2与j + 4等)。这可以处理偶数人的所有对。所以总计是2m轮。

如问题陈述中所述,2m-1轮是不可能的,所以2m是答案。

奇怪的情况更容易。在第j轮中,人j坐下,而j-1迎接j + 1,j-2迎接j + 2等,再次使用n轮。

答案 5 :(得分:0)

此处结果遵循加泰罗尼亚数字系列。 这是我在c ++中的代码

#include <bits/stdc++.h>
using namespace std;
long c[17] ;
void sieve(){
    c[0] = 1;
    c[1] = 1;
    for(int i =2;i<=15;i++){
        for(int j =0;j<i;j++){
            c[i] += c[j]*c[i-j-1];
        }
    }
}

int main(void){
    sieve();
    int t;
    scanf("%d",&t);
    while(t--){
        int n ;
        scanf("%d",&n);
        if(n%2!=0){
            cout<<"0"<<endl;
        }
        else{
            n = n>>1;
            cout<<c[n]<<endl;
        }
    }

    return 0;
}

答案 6 :(得分:0)

因为有n个人并且一次有2个人进行握手,而且如果说A与B握手和B与A握手,我们也不能算两次。 AB和BA都不能计数,这最终意味着不存在该安排。排列不是这种情况,但组合是...

因此,使用组合公式,求解后将变为: nC2 =>(n *(n-1))/ 2

因此,我们可以直接将公式应用于问题以获得答案。

答案 7 :(得分:-1)

人们可以与(n-1)+(n-2)+.....+1 ways进行握手。这是线性的

n圆桌会议方式