动手实现舞蹈链算法

ASAP实战:从仿真训练到现实部署,如何通过增量动作模型优化宇树G1的舞蹈表现 本文详细介绍了如何利用ASAP框架及其核心的增量动作模型,优化宇树G1机器人的舞蹈表现。通过从仿真预训练到现实后训练的两阶段流程,重点阐述了如何收集真机数据、训练增量动作模型以弥合仿真与现实鸿沟,并最终实现高表现力、稳定流畅的舞蹈部署,为机器人娱乐应用提供了实战解决方案。 阅读详情

把 简书 的文章转过来,这边看的人应该多点。

舞蹈链(Dancing links)实际上是一种数据结构,可以用来实现 X算法,以解决精确覆盖问题。

什么是精确覆盖(Exact Cover)问题呢?维基百科上对精确覆盖的定义如下:在一个全集 X 中若干子集的集合为 S。S* 是 S 的一个子集,当且仅当 X 中的每一个元素在 S* 中恰好出现一次时,S* 称之为一个精确覆盖。在计算机科学中,精确覆盖问题指找出这样的一种覆盖,或证明其不存在。这是一个NP-完全问题。

例如,S = {A,B,C,D,E,F} 是全集 X = {1,2,3,4,5,6,7} 的一个子集的集合,其中:
A = {1, 4, 7}
B = {1, 4}
C = {4, 5, 7}
D = {3, 5, 6}
E = {2, 3, 6, 7}
F = {2, 7}
那么,S 的一个子集 S* = {B, D, F} 是 X 的一个精确覆盖,因为 X 中的每个元素恰好在 S* 中出现了一次。

可以用 0-1 矩阵来表示精确覆盖问题。我们用矩阵的每行表示 S 的一个元素,也就是 X 的一个子集;用矩阵的每列表示 X 的一个元素。矩阵中的 1 代表这一列的元素存在于这一行对应的子集中,0 代表不存在。那么精确覆盖问题可以转化成求出矩阵若干行的集合,使得集合中的每一列恰好都有一个 1。

比如前面的问题可以用矩阵的形式表示成

1 2 3 4 5 6 7 A 1 0 0 1 0 0 1 B 1 0 0 1 0 0 0 C 0 0 0 1 1 0 1 D 0 0 1 0 1 1 0 E 0 1 1 0 0 1 1 F 0 1 0 0 0 0 1 \begin{array} {c|ccccccc} & 1 & 2 & 3 & 4 & 5 & 6 & 7 \\ \hline A & 1 & 0 & 0 & 1 & 0 & 0 & 1 \\ \color{#d00}{B} & \color{#d00}{1} & \color{#d00}{0} & \color{#d00}{0} & \color{#d00}{1} & \color{#d00}{0} & \color{#d00}{0} & \color{#d00}{0} \\ C & 0 & 0 & 0 & 1 & 1 & 0 & 1 \\ \color{#d00}{D} & \color{#d00}{0} & \color{#d00}{0} & \color{#d00}{1} & \color{#d00}{0} & \color{#d00}{1} & \color{#d00}{1} & \color{#d00}{0} \\ E & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ \color{#d00}{F} & \color{#d00}{0} & \color{#d00}{1} & \color{#d00}{0} & \color{#d00}{0} & \color{#d00}{0} & \color{#d00}{0} & \color{#d00}{1} \end{array} ABCDEF​1110000​2000011​3000110​4111000​5001100​6000110​7101011​​

那么选择红色的 B,D,F 能满足每列都恰好包含一个 1。

可以用 Knuth 提出的 X算法 来解决精确覆盖问题。X算法是一个非确定性的深度优先回溯算法。它的具体步骤如下:

  1. 如果矩阵 A A A为空(没有任何列),则当前局部解即为问题的一个解,返回成功;否则继续。
  2. 根据一定方法选择第 c 列。如果某一列中没有 1,则返回失败,并去除当前局部解中最新加入的行。
  3. 选择第 r 行,使得 A r , c A_{r, c} Ar,c​ = 1(该步是非确定性的)。
  4. 将第 r 行加入当前局部解中。
  5. 对于满足 A r , j A_{r, j} Ar,j​ = 1的每一列j,从矩阵 A A A中删除所有满足 A i , j A_{i, j} Ai,j​ = 1的行,最后再删除第 j 列。
  6. 对所得比 A 小的新矩阵递归地执行此算法。

让我们用 X算法 解决上面的精确覆盖问题。

首先,当前矩阵不为空,算法继续进行。那么先选择 1 最少的一列。因为 1,2,3,5,6 列都只有 2 个 1,因此我们随便选择 1 个,比如第 1 列。

1 2 3 4 5 6 7 A 1 0 0 1 0 0 1 B 1 0 0 1 0 0 0 C 0 0 0 1 1 0 1 D 0 0 1 0 1 1 0 E 0 1 1 0 0 1 1 F 0 1 0 0 0 0 1 \begin{array}{c|ccccccc} & \color{#d00}{1} & 2 & 3 & 4 & 5 & 6 & 7 \\ \hline A & \color{#d00}{1} & 0 & 0 & 1 & 0 & 0 & 1 \\ B & \color{#d00}{1} & 0 & 0 & 1 & 0 & 0 & 0 \\ C & 0 & 0 & 0 & 1 & 1 & 0 & 1 \\ D & 0 & 0 & 1 & 0 & 1 & 1 & 0 \\ E & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ F & 0 & 1 & 0 & 0 & 0 & 0 & 1 \end{array} ABCDEF​1110000​2000011​3000110​4111000​5001100​6000110​7101011​​

行 A 和 B 都含有 1,因此要在这两行中进行选择。

先尝试选择行 A。将行 A 加入到当前的解中。
1 2 3 4 5 6 7 A 1 0 0 1 0 0 1 B 1 0 0 1 0 0 0 C 0 0 0 1 1 0 1 D 0 0 1 0 1 1 0 E 0 1 1 0 0 1 1 F 0 1 0 0 0 0 1 \begin{array}{c|ccccccc} & \color{#AD3}{1} & 2 & 3 & \color{#AD3}{4} & 5 & 6 & \color{#AD3}{7} \\ \hline \color{#d00}{A} & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} \\ B & 1 & 0 & 0 & 1 & 0 & 0 & 0 \\ C & 0 & 0 & 0 & 1 & 1 & 0 & 1 \\ D & 0 & 0 & 1 & 0 & 1 & 1 & 0 \\ E & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ F & 0 & 1 & 0 & 0 & 0 & 0 & 1 \end{array} ABCDEF​1110000​2000011​3000110​4111000​5001100​6000110​7101011​​
行 A 的 1,4,7 列为 1,根据第 5 步,需要把所有在 1,4,7 列中含有 1 的行都删除掉,因此需要删除掉行 A,B,C,E,F,同时删除掉第 1,4,7 列
1 2 3 4 5 6 7 A 1 0 0 1 0 0 1 B 1 0 0 1 0 0 0 C 0 0 0 1 1 0 1 D 0 0 1 0 1 1 0 E 0 1 1 0 0 1 1 F 0 1 0 0 0 0 1 \begin{array}{c|ccccccc} & \color{#AD3}{1} & 2 & 3 & \color{#AD3}{4} & 5 & 6 & \color{#AD3}{7} \\ \hline \color{#AD3}{A} & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} \\ \color{#AD3}{B} & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} & 0 & 0 & 0 \\ \color{#AD3}{C} & 0 & 0 & 0 & \color{#d00}{1} & 1 & 0 & \color{#d00}{1} \\ D & 0 & 0 & 1 & 0 & 1 & 1 & 0 \\ \color{#AD3}{E} & 0 & 1 & 1 & 0 & 0 & 1 & \color{#d00}{1} \\ \color{#AD3}{F} & 0 & 1 & 0 & 0 & 0 & 0 & \color{#d00}{1} \end{array} ABCDEF​1110000​2000011​3000110​4111000​5001100​6000110​7101011​​
删除之后,矩阵只剩下行 D 和第 2,3,5,6 列:
2 3 5 6 D 0 1 1 1 \begin{array}{c|cccc} & 2 & 3 & 5 & 6 \\ \hline D & 0 & 1 & 1 & 1 \\ \end{array} D​20​31​51​61​​
进入递归,回到第 1 步,矩阵非空,算法继续执行。
再进入第2步,此时选择 1 最少的第 2 列,里面没有 1,因此返回失败,同时将行 A 从当前的解中移除;

算法进入另一个分支,选择行 B,并将其加入到当前的解中:
1 2 3 4 5 6 7 A 1 0 0 1 0 0 1 B 1 0 0 1 0 0 0 C 0 0 0 1 1 0 1 D 0 0 1 0 1 1 0 E 0 1 1 0 0 1 1 F 0 1 0 0 0 0 1 \begin{array}{c|ccccccc} & \color{#AD3}{1} & 2 & 3 & \color{#AD3}{4} & 5 & 6 & 7 \\ \hline A & 1 & 0 & 0 & 1 & 0 & 0 & 1 \\ \color{#d00}{B} & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} & 0 & 0 & 0 \\ C & 0 & 0 & 0 & 1 & 1 & 0 & 1 \\ D & 0 & 0 & 1 & 0 & 1 & 1 & 0 \\ E & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ F & 0 & 1 & 0 & 0 & 0 & 0 & 1 \end{array} ABCDEF​1110000​2000011​3000110​4111000​5001100​6000110​7101011​​
行 B 的第 1,4 列为 1,因此要把 1,4 列中包含 1 的行都删掉。需要删除掉行 A,B,C,再删除掉 1,4 列。
1 2 3 4 5 6 7 A 1 0 0 1 0 0 1 B 1 0 0 1 0 0 0 C 0 0 0 1 1 0 1 D 0 0 1 0 1 1 0 E 0 1 1 0 0 1 1 F 0 1 0 0 0 0 1 \begin{array}{c|ccccccc} & \color{#AD3}{1} & 2 & 3 & \color{#AD3}{4} & 5 & 6 & 7 \\ \hline \color{#AD3}{A} & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} & 0 & 0 & 1 \\ \color{#AD3}{B} & \color{#d00}{1} & 0 & 0 & \color{#d00}{1} & 0 & 0 & 0 \\ \color{#AD3}{C} & 0 & 0 & 0 & \color{#d00}{1} & 1 & 0 & 1 \\ D & 0 & 0 & 1 & 0 & 1 & 1 & 0 \\ E & 0 & 1 & 1 & 0 & 0 & 1 & 1 \\ F & 0 & 1 & 0 & 0 & 0 & 0 & 1 \end{array} ABCDEF​1110000​2000011​3000110​4111000​5001100​6000110​7101011​​
此时矩阵变为
2 3 5 6 7 D 0 1 1 1 0 E 1 1 0 1 1 F 1 0 0 0 1 \begin{array}{c|ccccc} & 2 & 3 & 5 & 6 & 7 \\ \hline D & 0 & 1 & 1 & 1 & 0 \\ E & 1 & 1 & 0 & 1 & 1 \\ F & 1 & 0 & 0 & 0 & 1 \end{array} DEF​2011​3110​5100​6110​7011​​
进入递归,回到第 1 步,矩阵非空,因此算法继续。
当前包含 1 最少的一列是第 5 列,那么将从第 5 列中选择含有 1 的行进行搜索。
  2 3 5 6 7 D 0 1 1 1 0 E 1 1 0 1 1 F 1 0 0 0 1 \begin{array}{c|ccccc} \ & 2 & 3 & \color{#d00}{5} & 6 & 7 \\ \hline D & 0 & 1 & \color{#d00}{1} & 1 & 0 \\ E & 1 & 1 & 0 & 1 & 1 \\ F & 1 & 0 & 0 & 0 & 1 \end{array}  DEF​2011​3110​5100​6110​7011​​

第 5 列中行 D 含有 1,因此选择行 D,将其加入当前解中,算法进入新的一层搜索。
2 3 5 6 7 D 0 1 1 1 0 E 1 1 0 1 1 F 1 0 0 0 1 \begin{array}{c|ccccc} & 2 & \color{#AD3}{3} & \color{#AD3}{5} &\color{#AD3}{6} & 7 \\ \hline \color{#d00}{D} & 0 & \color{#d00}{1} & \color{#d00}{1} & \color{#d00}{1} & 0 \\ E & 1 & 1 & 0 & 1 & 1 \\ F & 1 & 0 & 0 & 0 & 1 \end{array} DEF​2011​3110​5100​6110​7011​​
行 D 的第 3,5,6 列包含 1,我们要删掉这几列中包含 1 的所有行,同时删掉这几列
2 3 5 6 7 D 0 1 1 1 0 E 1 1 0 1 1 F 1 0 0 0 1 \begin{array} {c|ccccc} & 2 & \color{#AD3}{3} & \color{#AD3}{5} &\color{#AD3}{6} & 7 \\ \hline \color{#AD3}{D} & 0 & \color{#d00}{1} & \color{#d00}{1} & \color{#d00}{1} & 0 \\ \color{#AD3}{E} & 1 & \color{#d00}{1} & 0 & \color{#d00}{1} & 1 \\ F & 1 & 0 & 0 & 0 & 1 \end{array} DEF​2011​3110​5100​6110​7011​​
那么我们需要删掉行 D,E 和第 3,5,6 列,矩阵变为
2 7 F 1 1 \begin {array}{c|cc} & 2 & 7 \\ \hline F & 1 & 1 \end{array} F​21​71​​
再次递归执行,回到第 1 步,矩阵非空,因此算法继续
选择当前包含 1 最少的一列,这里选择第 2 列。第 2 列中只有行 F 包含 1, 因此选择行 F

将行 F 加入到当前解中,算法进入第 3 层搜索
2 7 F 1 1 \begin{array} {c|cc} & 2 & 7 \\ \hline \color{#d00}{F} & \color{#d00}{1} & \color{#d00}{1} \end{array} F​21​71​​
行 F 中第 2,7列为 1,第 2,7 列中行 F 包含 1,因此移除行 F 和第 2,7 列
2 7 F 1 1 \begin{array} {c|cc} & \color{#AD3}{2} & \color{#AD3}{7} \\ \hline \color{#AD3}{F} & \color{#d00}{1} & \color{#d00}{1} \end{array} F​21​71​​
算法再次进入递归执行,回到第 1 步,此时所有的列都被移除了,矩阵为空,因此返回成功,找到了一个解:{B, D, F}

继续搜索,没有其他可以选择的行,返回上一层;

第 2 层也没有其他可以选择的行,再返回上一层;

第 1 层也没有其他可以选择的行,再返回上一层;

第 0 层也没有其他可以选择的行,算法终止。

以上就是 X 算法的执行过程。Knuth 提出 X 算法主要是为了说明舞蹈链的作用,他发现用舞蹈链来执行 X 算法效率特别高。那么什么是舞蹈链呢?它是基于双向链表的一种数据结构。

让我们先来看看双向链表:

Doubly linked list

上图是一个简单的双向链表,每个节点有两个指针,分别指向自己的前驱和后继节点。那么如果我们想把其中一个节点,比如 B 从链表中删掉,只需要执行下面的操作:

B.left.right = B.right
B.right.left = B.left

注意:此时虽然 B 从链表中移除了,但它的两个指针依然保持不变,还是指向之前的前驱和后继节点。

B is removed

因此,如果我想把 B 再添加到链表原来的位置上,此时并不需要修改 B 的指针,只需要再把 B 的前驱和后继节点的指针恢复就可以了:

B.left.right = B
B.right.left = B

理解了这一点之后,让我们再来看看舞蹈链的结构是怎么样的:

Dancing links

上面这个图是一个舞蹈链的结构,描述的是前面 X 算法中用到的矩阵。它由几部分构成:

最上面的蓝色部分是一个水平的环状双向链表。最左边是头节点,它是整个数据结构的根节点。其余是列头节点,每个代表矩阵中的一列。

每一列又是一个纵向的环状双向链表。除了最上面的列头节点,其他的每个节点都代表前面的矩阵中的一个 1。这实际上是一个稀疏矩阵,为了优化存储和效率,只保留了值为 1 的节点,把每个节点按顺序保存到数组中。最早的 Dancing Links 算法,也就是 Knuth 在 2000 年发表的论文中,下面的每一行也都是一个双向链表。但后来他发现每一行在算法执行过程中实际上不会发生变化,因此他把水平的双向链表取消了,只保留了最顶上的列头节点之间的水平双向链表。下面的每一行之间的前后节点可以直接通过数组的索引得到。两边是Space节点,用来标记一行的开始和结束。

每个普通节点 A 都包含 4 个 字段,A.up 和 A.down 代表双向链表的两个指针,分别指向 A 上面和下面的节点。还有一个 A.col ,指向 A 所在列的头节点,需要根据这个字段定位到节点所在的列。另外还有一个 A.row,主要是方便在递归的过程中缓存当前的解。

列头节点还要再多几个字段,left 和 right 分别指向水平双向链表的左节点和右节点。另外还有一个 count 字段,代表这一列当前一共有几个元素。X 算法的第 2 步,选择 1 最少的列时会用到这个字段。

理解了舞蹈链的数据结构之后,我们再来看看是怎样用舞蹈链来实现 X 算法的。这部分算法很精妙,也是舞蹈链这个名字的来由,通过对链表上的节点反复删除和插入实现了递归的回溯,就好像一个个链表在舞台上翩翩起舞一样。

具体的算法实现可以参照 Knuth 的论文,我们还是用图的方式来说明一下。

  • 首先,判断链表是否为空,可以通过 head.right == head 来判断。如果为空则返回,并输出当前的解。

  • 不为空则选择当前节点数最少的列。如果只有列头节点,则返回失败。

选择一列

  • 遍历这一列的每个节点,开始进行覆盖操作:

    1. 首先将节点所在行作为解的一部分,加入到当前解中;
      选择列中的一个节点所在的行

    2. 遍历这一行的所有节点,将每个节点所在列都删除掉,同时删除掉与这些列有交集的所有行:
      2a. 遍历节点所在列的每个节点,将每个节点所在行的所有节点从它所在的列中移除掉,同时将列头节点的计数减 1:

    node.up.down = node.down
    node.down.up = node.up
    col_node.count -= 1
    

    2b. 还要将这一列从链表中移除:

    col_node.left.right = col_node.right
    col_node.right.left = col_node.left
    

    移除了选择行的所有列,和每一列有交集的所有行

  • 进入递归调用,判断链表是否为空;

  • 不为空则选择节点数最少的列,再遍历这一列的节点,进行覆盖操作:

  • 移除掉所有节点之后,进入递归调用,发现链表不为空,但节点数最少的列中没有普通节点了,返回失败;

  • 开始做链表的还原操作。注意还原的顺序需要和移除的顺序相反。如果我们是从上至下,从左至右移除节点,那么还原的时候就从右至左,从下至上。否则的话可能会出现问题,导致一个节点被还原多次,这样列中节点的计数就不准确了。

    node.up.down = node
    node.down.up = node
    col_node.count += 1
    
  • 并且把删除的列也取消覆盖

    col_node.left.right = col_node
    col_node.right.left = col_node
    
  • 递归返回到上一层,还原之后,发现列中没有其他节点可以选择,再返回到上一层,选择下一个节点所在的行。
    选择另一个节点所在行

  • 和之前的方法相同,遍历这一行的所有节点,将每个节点所在列都删除掉,同时删除掉与这些列有交集的所有行:
    移除了选择行的所有列,和每一列有交集的所有行

  • 再选择节点最少的列,遍历这一列的所有节点的所在行:
    选择节点最少的列,遍历这一列的节点所在行

  • 遍历这一行的所有节点,删除掉每个节点所在列,以及与这些列有交集的所有行:
    移除了选择行的所有列,和每一列有交集的所有行

  • 再次进入递归调用,判断矩阵不为空,选择节点最少的一列,遍历每个节点,删除掉所在行的所有列,与这些列有交集的所有行,最后我们得到一个空矩阵。
    空链表,只剩头节点

  • 此时将得到的解输出,并返回,接下来还要进行还原操作,然后搜索下一个解。

以上就是舞蹈链算法的执行过程。

MambaTrack实战:如何在舞蹈和体育场景中实现高效多目标跟踪(附代码解析) 本文深入解析了MambaTrack在舞蹈和体育等复杂场景中实现高效多目标跟踪的实战方法。针对目标运动非线性强、遮挡频繁等挑战,MambaTrack创新性地利用状态空间模型Mamba构建运动预测器,并结合轨迹补丁模块有效处理目标丢失与重现,显著提升了跟踪关联精度。文章提供了核心代码解析与部署调优经验。 阅读详情

相关推荐

Dancing Links X(跳舞链)

双向十字交叉循环链表求解精确覆盖、重复覆盖。 骨牌覆盖、N皇后问题的高效解法。

英雄哪里出来 32万+

链表上的舞者——舞蹈链(DLX算法)

在整个求解过程中,指针在数据间跳跃着,就像精巧设计的舞蹈一样,故Donald E.Knuth把它称为Dancing Links(中文译名舞蹈链)。 目录 1.1一类被称为精确覆盖的问题 1.2经典的精确覆盖问题举例——矩阵覆盖 1.2.1问题描述 1.2.2从暴力算法到X算法 第二部分:精确覆盖问题的X算法 2.1X算法分析——矩阵覆盖问题的解决 第三部分:用于X算法的数据结构——双向十字循环链表 3.1主角登场——双向十字循环链表概览 3.2详细分析——双向十字循环链表的操作 ...

m0_52447591的博客 6254

舞蹈链数独求解算法

舞蹈链算法求解数独

dancing links x(舞蹈链算法)详解

dancing links x 详解 大佬万仓一黍的blog 夜深人静写算法(九)- Dancing Links X(跳舞链) /* Dancing Links 高效搜索算法 1) 如果矩阵A没有列(即空矩阵),则当前记录的解为一个可行解;算法终止,成功返回; 2) 否则选择矩阵A中“1”的个数最少的列c;(确定性选择) 3) a.如果存在A[r][c]=1的行r,将行r放...

dajiangyou123456的博客 5552

java数独求解算法

主要思想:用二维数组表示数独,将为0的下标用一维数组表示,从小到大依次试探每一个可能的数,填充,若皆不可能,则回退到上一个数从上一个数的可能值+1开始,同时将以后的数重新置为0,特别注意的是,回退后求得解后无需再返回上一层,直接结束即可

104报文解析工具

可选择包含报文的文本文件或日志文件进行解析,可选择按条数范围或时间范围,输出结果可以在报文解析显示区,也可以输出到文件。可以对文本内容的报文文件进行高级分析,包括遥信遥测等通讯数据的具体信息,通讯帧的统计,通讯次数的统计,各种错误的分析,报文的定位功能,传输的文件具体内容等。输入完成后点击工具栏的解析报文按钮或使用右键菜单的解析就可以对报文进行解析。在报文输入区输入待解析报文并解析后,解析结果就显示在报文解析显示区和报文定位展示区及报文定位条目区。当有多条报文解析后,可以通过报文列表树具体定位某条报文。

XZHOUMIN的博客 5948

算法——舞蹈链算法

舞蹈链算法通过双向链表的动态调整,将精确覆盖问题的搜索效率提升到极致。尽管实现复杂,但它在处理组合优化问题时表现卓越,尤其适合约束严格的场景。理解其核心在于掌握链表操作与回溯思想的结合。

oopxiajun博客专栏 2140

virtuoso--DFF

27-实验课-std_cell2

qq_61440044的博客 2004

舞蹈链,DLX算法详解,OJ精讲,详细代码

如何将实际问题抽象为精确覆盖问题?

EQUINOX1的博客 1987

【阿里云大模型高级工程师ACP习题集】2.5 优化RAG应用提升问答准确度(⭐️⭐️⭐️ 重点章节!!!)

【摘要】这是我精心整理出对应的习题集,里面足足有 30 道题目,从基础概念到深度拓展,全方位覆盖章节重点、难点。不管你是想检验自己的学习成果,还是想针对薄弱环节进行强化训练,它都能完美适配!

davidkorhenn的博客 1105

windows10系统上安装最新版mysql 8.0详细步骤

windows10系统上安装最新版mysql 8.0详细步骤

glei20的博客 6715

AI舞蹈动作生成技术解析:从算法原理到工程实践

TCN部分nn.ReLU(),nn.ReLU()# Transformer部分# 输出层# x形状: (batch, seq_len, input_dim)x = x.transpose(1, 2) # 转为(batch, input_dim, seq_len)x = x.transpose(1, 2) # 转回(batch, seq_len, 128)本文提出的TCN-Transformer混合架构在保持动作质量的同时,显著提升了生成效率。

2600_94959861的博客 844

MuJoCo与Isaac Sim的无缝对接:利用USD导出功能实现强化学习场景的跨平台迁移

本文详细介绍了如何通过USD导出功能实现MuJoCo与Isaac Sim的无缝对接,助力强化学习场景的跨平台迁移。文章解析了USD格式的核心优势,包括分层合成、物理属性继承和时间轴动画,并提供了从MJCF到USD的完整转换流程及在Isaac Sim中的高级应用技巧,帮助开发者高效迁移和优化强化学习环境。

weixin_29073241的博客 515

AI舞蹈动作生成实战:从提示词设计到工程化落地

基于火山引擎豆包大模型,从零搭建一个实时语音通话应用。它不是简单的问答,而是需要你亲手打通 ASR(语音识别)→ LLM(大脑思考)→ TTS(语音合成)的完整 WebSocket 链路。对于想要掌握 AI 原生应用架构的同学来说,这是个绝佳的练手项目。架构理解:掌握实时语音应用的完整技术链路(ASR→LLM→TTS)技能提升:学会申请、配置与调用火山引擎AI服务定制能力:通过代码修改自定义角色性格与音色,实现“从使用到创造”从0到1构建生产级别应用,脱离Demo,点击打开。

2600_94960224的博客 829

STM32新手必看:AHT20温湿度传感器实战指南(附完整I2C代码)

本文详细介绍了如何使用STM32驱动AHT20温湿度传感器,包括硬件连接、I2C通信协议解析、驱动代码优化及实战调试技巧。通过对比AHT20与DHT11、SHT30等传感器的性能,突出AHT20的高性价比优势,并提供完整的I2C代码示例,帮助新手快速上手嵌入式传感器开发。

weixin_29163857的博客 293

深度解析与实战:长短时记忆网络(LSTM)在股票走势预测中的应用(基于Python + PyTorch)

本文全面探讨了LSTM在股票价格预测中的应用,从理论基础到实践操作。文章首先强调了股票市场预测的重要性,并介绍了LSTM网络结构及其在处理时间序列数据中的优势。接着,详细说明了数据预处理的关键步骤,包括数据收集、清洗、特征选择和归一化。文章还讨论了LSTM模型的构建、训练和评估,并提供了Python及PyTorch的实操案例。最后,总结了LSTM在股票预测的成果,并提出了未来研究的方向,如模型优化和特征工程,旨在帮助读者掌握LSTM在股票价格预测中的应用,并探索提升模型性能的方法。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 2100

**听见律动,舞出精彩 – 音乐驱动的舞蹈合成**

听见律动,舞出精彩 – 音乐驱动的舞蹈合成 在探索人工智能与艺术融合的道路上,我们经常惊叹于那些能够捕捉到人类情感并与之共舞的技术创新。今天,我将向大家介绍一个令人兴奋的开源项目——Listen, Denoise, Action(简称LDA),它以独特的方式结合了音频分析和运动合成,带来了一场舞蹈革命。 项目介绍 LDA项目基于论文《Listen, Denoise, Action! Audio-d...

gitblog_00057的博客 601

麻雀搜索算法(SSA)详解:从鸟群智能到优化实践

麻雀搜索算法(SSA)是一种新型群智能优化算法,模拟麻雀群体的觅食行为和反捕食机制。该算法将优化问题转化为麻雀群体对食物源的搜索过程,通过发现者、加入者和警戒者的角色分工实现高效优化。SSA具有原理新颖、参数合理、收敛快速等特点,在函数优化、工程设计和机器学习等领域展现出良好应用前景。算法通过数学模型模拟麻雀的觅食策略,包括发现者全局探索、加入者局部开发和警戒者危险预警机制,有效平衡了全局搜索与局部开发能力。SSA相比传统优化算法具有更好的收敛性和优化效果。

qq_42212808的博客 1072

终极算法实战指南:从数独求解到排列组合优化的完整教程

算法实战是每个程序员成长的必经之路,而GitHub加速计划中的reci/recipes项目提供了绝佳的算法实践平台。这个开源项目包含了丰富的C++算法实现,从经典的数独求解器到高效的排列组合优化算法,为初学者和进阶开发者提供了宝贵的学习资源。今天,我们将深入探索这个项目的核心算法实现,掌握从基础到进阶的算法实战技巧。 ## 🔍 项目概览:算法实战的宝藏库 reci/recipes项目是一个专

gitblog_00027的博客 398

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

C++实现高效数独生成器:从回溯算法到并行优化

回溯算法是解决约束满足问题的经典方法,其核心原理是通过递归尝试与撤销操作,系统地探索所有可能的解空间。在数独生成这类组合优化问题中,回溯法能确保找到有效解,但面临搜索空间巨大的挑战。通过引入位运算进行状态压缩,可以将行列宫的约束检查复杂度降至O(1),并采用最小候选数优先策略大幅剪枝,这是提升算法效率的关键技术。这些优化不仅体现了C++在性能敏感场景下的价值,也为游戏内容生成、自动化测试等需要海量逻辑谜题的工程实践提供了高效解决方案。本文以数独生成为例,深入探讨了如何结合位运算和智能回溯,实现微秒级的高性能

weixin_30873847的博客 379

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

AI舞蹈生成技术解析:从提示词设计到动作合成的工程实践

基于火山引擎豆包大模型,从零搭建一个实时语音通话应用。它不是简单的问答,而是需要你亲手打通 ASR(语音识别)→ LLM(大脑思考)→ TTS(语音合成)的完整 WebSocket 链路。对于想要掌握 AI 原生应用架构的同学来说,这是个绝佳的练手项目。架构理解:掌握实时语音应用的完整技术链路(ASR→LLM→TTS)技能提升:学会申请、配置与调用火山引擎AI服务定制能力:通过代码修改自定义角色性格与音色,实现“从使用到创造”从0到1构建生产级别应用,脱离Demo,点击打开。

2600_94959990的博客 325

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

MusePose终极指南:三步完成AI虚拟人舞蹈视频生成

想要让静态人物图片动起来,跳起优美的舞蹈吗?MusePose正是你需要的AI虚拟人视频生成神器!这个基于扩散模型和姿态引导的开源框架,能够根据给定的姿态序列,生成与参考图像中人物动作一致的舞蹈视频。无论你是内容创作者、动画爱好者还是技术探索者,MusePose都能为你打开虚拟人生成的新世界。 ## 🚀 从零开始:快速搭建你的AI舞蹈工作室 ### 第一步:环境配置与权重下载 MusePos

gitblog_00431的博客 797

AI发光短裙舞蹈视频制作教程,小白也能快速上手

的格式(含图文结构与封面标题建议)?

564

Qwen3-VL-30B能否理解舞蹈动作图像?人体姿态语义解析

本文探讨通义千问的多模态大模型Qwen3-VL-30B如何理解舞蹈动作图像,实现从视觉输入到语义解释的端到端解析。模型基于Transformer架构,无需关键点检测即可识别动作细节、风格与情感,支持零样本迁移与自然语言反馈,适用于教学、康复与内容创作等场景。

weixin_36235398的博客 553

基于ROS2与MoveIt的宇树G1人形机器人传统舞蹈动作规划实战

机器人运动规划是机器人技术的核心领域之一,它涉及如何让机器人安全、高效地完成从起点到目标点的移动或动作序列。其基本原理是通过算法(如基于采样的规划、优化方法等)在考虑机器人运动学、动力学约束及环境障碍物的情况下,生成可行的运动轨迹。这项技术的价值在于将高级任务指令转化为底层关节或轮子的具体控制命令,是实现机器人自主作业、人机协作等复杂应用的基石,广泛应用于工业装配、物流分拣、医疗服务乃至仿生机器人表演等场景。本文聚焦于利用ROS2(机器人操作系统2)和MoveIt运动规划框架,针对宇树G1这款高自由度人形机

weixin_34194359的博客 372

如何用MusePose快速生成虚拟人舞蹈视频:完整指南与实战技巧

想要让静态图片中的人物"活"起来,跟随音乐翩翩起舞吗?MusePose正是这样一个神奇的虚拟人视频生成框架,它能根据姿态序列让参考图像中的人物动起来,创造出令人惊艳的舞蹈视频。无论你是AI爱好者、内容创作者还是开发者,这个开源工具都能帮你轻松实现虚拟人动画制作。🎬 ## 🔥 为什么选择MusePose? MusePose的核心优势在于它的姿态驱动图像转视频能力,这意味着你可以通过简单的操作

gitblog_00983的博客 360
上一篇: 使用UrlRewriteFilter如何在Tomcat crossContext的情况下上传文件
下一篇: Tomcat无缘无故停止
windsome
博客等级 码龄19年 5粉丝 26原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值