Algorithm 每对相邻数字之间的差值大于1的不同序列有多少

Algorithm 每对相邻数字之间的差值大于1的不同序列有多少,algorithm,Algorithm,我只是发现这样的问题 给你N个不同的整数,你知道有多少个不同的序列,每个相邻的数对之间的差值大于1吗 当整数是“1233”时,答案是零,当整数是“531”时,答案是6,因为“1351”“1533”“315”“351”“513”“531”满足这个问题,我只是尽了我所能,但我无法解决它,所以我的问题是,如何写一个算法来解决它 谢谢 这是我的节目 int n;bool vi[30];int a[30];int b[30];int counter = 0; void dfs(int k) { i

我只是发现这样的问题

给你N个不同的整数,你知道有多少个不同的序列,每个相邻的数对之间的差值大于1吗

当整数是“1233”时,答案是零,当整数是“531”时,答案是6,因为“1351”“1533”“315”“351”“513”“531”满足这个问题,我只是尽了我所能,但我无法解决它,所以我的问题是,如何写一个算法来解决它

谢谢

这是我的节目

int n;bool vi[30];int a[30];int b[30];int counter = 0;
void dfs(int k)
{
    if ( k == n)
    {
        for (int i = 2; i <= n; i ++)
            if (fabs(b[i] - b[i - 1]) <= 1) return ;
        counter ++;
        return ;
    }
    for (int i = 0; i < n; i ++)
    {
    if (!vi[i])
    {
        b[k + 1] = a[i];
        vi[i] = true;
        dfs(k + 1);
        vi[i] = false;
        }
    }
}
int main (void)
{
        cin >> n;
        for (int i = 0; i < n; i ++)
            cin >> a[i];
        memset(vi, 0, sizeof(vi));
        for (int i = 0; i < n; i ++)
        {
            vi[i] = true;b[1] = a[i];dfs(1);vi[i] = false;
        }
        cout << counter << endl;
    return 0;
}
intn;布尔六世[30];INTA[30];int b[30];int计数器=0;
无效dfs(整数k)
{
如果(k==n)
{
对于(int i=2;i n;
对于(int i=0;i>a[i];
memset(vi,0,sizeof(vi));
对于(int i=0;i“有多少不同的序列…”这个问题的答案可以在不列举每一个组合的情况下解决。这是一件好事,因为
25!
大约是1.55 x 10^24,或者比任何现有计算机在一秒钟内或一年内所列举的要多得多

这是一个数学问题,特别是组合数学。有关如何解决该问题的信息,请参阅,也可能参阅。

似乎“中间相遇”原则可以提供合理的工作时间

草图:

将数字列表分成相等的部分(+-1表示奇数长度)。有C(N,N div 2)变体

计算所有固定的最后和第一个元素的前半部分和后半部分的有效排列数(递归)。将兼容的最后和第一个元素的计数相乘

编辑:找到更可靠的变体

让我们用FullSet=(A,B,C,D) 为了计算有效置换,从A开始,我们应该计算不带A的集合(B,C,D)的有效置换,从值开始,与A兼容。这同样适用于从B开始的有效置换,等等

我最初编写了递归函数来访问所有初始值,并计算没有这些值的集合的有效置换。它只适用于小集合

然后我用记忆法来记忆组合[InitialValue,Set]的计数(以避免对同一集合重复计算)。这是一种上下动态规划

最后,我将动态编程从自上而下的方式转换为升序方式——这是可能的,因为我们可以按顺序填充记忆表

复杂度是O(N^2*2^N),内存消耗是O(N*2^N),因为我们应该检查(几乎)整个集合的所有2^N子集。因此,我可以对n1//兼容的数字使用此方法 计数:=计数+备忘录[msk xor(1个shl索引),i]; //对不带索引元素的集合使用上一个结果,从ith开始 备忘录[msk,索引]:=计数; 结束; 结束; 计数:=0; 对于索引:=0到N-1 do 计数:=计数+备忘录[掩码,索引];
所用示例(1、2、4、5)的结果为8
手动检查:1425 1524 2415 2514 4152 4251 5142 5241

为了找到比O(n!)方法更快的解决方案,枚举所有置换并检查它们-我要注意,这个问题是一个计算图(V,E)上所有置换的实例其中V是原始列表的成员,E是连接可以相邻的成员的边(因此第二个示例是V={1,3,5}和E={(1,3)、(3,5)、(1,5)})


我不知道如何有效地计算哈密顿路径,但也许这就是解决问题的方法。

O(n!)对你来说足够快吗?n有多大?你可以参考问题中的O(n!)解决方案。@penartur我只有一秒钟,n小于或等于25。@Kevin我只有一秒钟,n小于或等于25。@HighPerformanceMark好的,我使用了深度搜索来解决它,但我的朋友说如果我只有一秒钟的时间来解决,那么我的程序将无法运行。
var
  A: TArray<Byte>;
  Memo: array of array of Int64;
  N, Mask, msk, index, i: Integer;
  Count: Int64;
  OnlyOneOneBit: Boolean;

begin
  A := TArray<Byte>.Create(1, 2, 4, 5);

  N := Length(A);
  Mask := (1 shl N) - 1;//binary 000111111 with n ones

  SetLength(Memo, 1 shl N {2^N}, N);

  for msk := 1 to Mask do begin // all possible subsets, excluding empty one
    OnlyOneOneBit := 0 = (msk and (msk - 1));
    for index := 0 to N - 1 do
       if OnlyOneOneBit then
         Memo[msk, index] := (msk shr index) and 1 // 1 if indexth bit = 1 else 0
       else if 0 <> ((msk shr index) and 1) then begin
         Count := 0;
         for i := 0 to N - 1 do
           if Abs(A[i] - A[index]) > 1 then //compatible numbers
              Count := Count + Memo[msk xor (1 shl index), i];
     //use previous result for the set without index element, starting with ith
         Memo[msk, index] := Count;
       end;
  end;

  Count := 0;
  for index := 0 to N - 1 do
    Count := Count + Memo[Mask, index];