假设我有两个大小为m
和n
的数组:
a[1] a[2] a[3] ..... a[m]
和
b[1] b[2] b[3] ..... b[n]
我想形成一个合并这两个数组的新数组,这样在新的m + n
元素数组中,a[i]
始终位于a[i + 1]
之内,而b[i]
总是放在b[i + 1]
之前。例如,a[1] a[2] b[1] b[2]... b[n] a[m]
将是有效数组,但a[2] a[1] b[1] b[2] ... b[n] a[m]
不会。给定m
和n
,允许重复时可以使用多少个此类组合?
我有直觉来解决问题:
- b[1] - b[2] - b[3] - ..... - b[n]
我可以将a[1]
放在数组n - 1
中的任何b
个地方,考虑到前面和最后一个地方,我有n + 1
种放置方式a[1]
。如果我将a[1]
置于首位(就在b[1]
之前),我现在可以将a[2]
放在n + 1
个地方。但是,如果我在a[1]
之后放置b[1]
,我会n
方式放置a[2]
。我可以递归地为所有a[i]
1 <=i <= n
应用此方法。但我找不到任何数学公式来表达解决方案,除了我无法理解在允许重复时如何处理。
答案 0 :(得分:3)
考虑这个问题的一种方法是 - 不是按顺序列出元素,而是考虑在每个时刻选择是选择第一个未使用的A还是第一个未使用的B.所有可能的“选择A”和“选择B”的排序将产生产生这些序列的所有可能方式。
如果你假设所有元素都是不同的,那么答案将通过你可以置换m A序列后跟n B的方式的数量来给出。这是由
给出的 (m + n)!
-----------
m! n!
但是,在有一些重复元素的情况下,我没有答案。如果我想到任何事情,我一定会更新这个答案。
与此同时,我希望这有帮助!
答案 1 :(得分:1)
您正在寻找Stars and Bars公式。阵列A的位置是箱子;在每个位置,将插入来自A的相应元素和来自B的任意数量的元素。 (选择哪些元素已经由它们的原始顺序决定,因此我们将它们视为无法区分。)如果A中有(n-1)个元素(在一端添加一个bin)和B中有k个元素,则公式给出的是二项式系数
n + k - 1
( )
k
= ( (n+k-1)! / ( k! (n-1)! )
= (a.size() + b.size())! / (a.size()! * b.size()!)
与templatetypedef的答案相同:)
实际上计算这些大数的商是另一个问题。在大多数语言中,分子通常会产生整数溢出。 C ++中的一个简单策略(不一定是最优的)将是
unsigned long long gcd( unsigned long long &a, unsigned long long &b )
{ return b? gcd( b, a % b ) : a; }
std::vector< std::size_t > numerator( a.size() ); // factors of (a+b)!/b!
std::iota( numerator.begin(), numerator.end(), b.size()+1 );
for ( std::size_t afactor = 2; afactor != a.size()+1; ++ afactor ) {
std::size_t reduced = afactor;
for ( auto &&nfactor : numerator ) {
auto common = gcd( afactor, nfactor );
nfactor /= common;
reduced /= common;
if ( reduced == 1 ) goto next_afactor;
}
throw std::logic_error( "Fractional combinations" );
next_afactor: ;
}
return std::accumulate( numerator.begin(), numerator.end(), 1,
std::multiplies< std::size_t >() );