动态规划之序关系计数问题(同时介绍了递推解法)

"这篇博客探讨了如何使用动态规划算法来计算n个数以特定符号"<<<"排列时的不同序关系数。算法要求空间复杂度为O(n),时间复杂度为O(n^2)。博主给出了两种方法,一种是动态规划法,通过二维数组dp计算递推关系,另一种是递推法,但递推法的时间复杂度不满足题目的要求。博客还解释了递推法的思路,即通过组合数计算不同分界线位置的序关系数量。"

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:用关系 " < < < "和 " = = = "将3个数 A 、 B 、 C A、B、C ABC依序排列时,有13种不同的序关系: A = B = C , A = B < C , A < B = C , A < B < C , A < C < B , A = C < B , B < A = C , B < A < C , B < C < A , B = C < A , C < A = B , C < A < B , C < B < A A=B=C,A=B<C,A<B=C,A<B<C,A<C<B,A=C<B,B<A=C,B<A<C,B<C<A,B=C<A,C<A=B,C<A<B,C<B<A A=B=CA=B<CA<B=CA<B<CA<C<BA=C<BB<A=CB<A<CB<C<AB=C<AC<A=BC<A<BC<B<A。若要将 n n n 个数依序进行排列,试设计一个算法,计算出有多少种不同的序关系(是计算数目,不是给出各种排列)。要求算法的空间复杂性为 O ( n ) O(n) O(n),时间复杂性为 O ( n 2 ) O(n^2) O(n2)

若用 A [ i , j ] A[i,j] A[i,j] 表示用 j j j 个" < < < "号连接 i i i 个数时产生的不同序关系数,并约定当 j > i − 1 j>i-1 j>i1 时, A [ i , j ] = 0 A[i,j]=0 A[i,j]=0 ,另外显然 A [ i , 0 ] = 1 , i ∈ [ 1 , n ] A[i,0]=1, i\in[1,n] A[i,0]=1,i[1,n]

A [ i , j ] = ( j + 1 ) ( A [ i − 1 , j − 1 ] + A [ i − 1 , j ] ) A[i,j]=(j+1)(A[i-1,j-1]+A[i-1,j]) A[i,j]=(j+1)(A[i1,j1]+A[i1,j])

考虑 i i i 个数是由 i − 1 i-1 i1 个数增加一个 x x x 得到的,则分为两种情况: ①增加 x x x 之前有 j − 1 j-1 j1 个 " < < < " ; ②增加 x x x 之前有 j j j 个 " < < < "。另外, x x x j + 1 j+1 j+1 种可能性,这是因为,若把相等数视为同一个数,则 j j j 个 “ < < <” 的连接 i i i 个数的情况为: S 1 < S 2 < ⋯ < S j + 1 S_1 < S_2 < \cdots < S_{j+1} S1<S2<<Sj+1,其中 S k S_k Sk 是所有数值等于 x k x_k xk 的数的集合。

//动态规划法
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[][] dp=new int[n+1][n+1];
        for(int i=1;i<=n;i++){
            for(int j=0;j<=i-1;j++){
                if(j==0){
                    dp[i][0]=1;
                }else{
                    dp[i][j]=(j+1)*(dp[i-1][j-1]+dp[i-1][j]);
                }
            }
        }
        int sum=0;
        for(int i=0;i<=n;i++){
            sum+=dp[n][i];
        }
        System.out.println(sum);
    }
}
//递推法
int  Orderings( int  n)
 {
    A[0]=1;
    for(int j=1;j<=n-1;j++)
      A[j]=0;
    for(int i=2;i<=n;i++)
      for(int j=i-1;j>=1;j--)
        A[j]=(j+1)*(A[j-1]+A[j]);
    int total=0;
    for(int j=0;j<=n-1;j++)
       total+=A[j];
 return total;
}   
递推法,复杂度不满足题目要求:
简单的说就是:存在K,使得a1=a2=a3=a4...ak<ak+1....an成立。以<为分界线。后面的那一部分是子问题。
选取K个数的组合数为C(n,k)=c(n-1,k-1)+c(n-1,k);
这是高中的知识,就是说n个人中有一个特例,c(n-1,k-1)表示这个人一定在其中,c(n-1,k)表示这个人不选中。
加上后面的子问题退出递推式为g(n),g(n)表示N个数时的序关系数。g(n)=C(n,k)*g(n-k)   k from 1 to n。
其实组合问题本来就是一个递归,你要求最后面的值你就得先求前面的值,这也是动态规划的思想之一

递推法代码实现的巧妙之处:代码先计算出 i = 2 i=2 i=2 时对应的 A [ j ] A[j] A[j],当 i = 3 i=3 i=3 时,代码 A [ j ] = ( j + 1 ) ∗ ( A [ j − 1 ] + A [ j ] ) A[j]=(j+1)*(A[j-1]+A[j]) A[j]=(j+1)(A[j1]+A[j])中,右侧 A [ j ] A[j] A[j] 对应的时上一步的结果( i = 2 i=2 i=2 )时,因此得到的当前步( i = 3 i=3 i=3 )的结果,以此类推。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anonymity~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值