单调回文分解(动态规划)

单调回文分解
来源
Greater New York 2002(Z0J1353)


题目描述:


一串正整数序列如果从左往右读过去,和从右往左读过去,完全是一样的,则这串正整数称为是回文的,

例如:


23 11 15 1 37 37 1 15 11 23
1123477107743211


一个回文正整数串如果从左边到中间这些数是非递减的从中间到右边的数是非递增的,那么这个回文正整数串就称为是单调回文的。例如上述的2个例子中,第1个例子不是单调回文的,而第2个例子是单调回文的。
一个单调回文正整数串,如果所有正整数之和为N,则称它是整数N的单调回文分解。例如,1~8的所有单调回文分解为:


1: (1)
2: (2), (1 1)
3: (3), (1 1 1)

4:(4),(1 2 1),(2 2),(1 11 1)
5:(5),(13 1),(11111)
6:(6),(141),(2 2 2),(1121 1),(3 3),(122 1),(111111)
7:(7),(151),(2 3 2),(11311),(1111111)
8:(8),(161),(2 4 2),(11411),(12221),(1112 111),(44),(1331),(2222),(112211),(1111111 1)
编写一个程序,计算一个正整数的单调回文分解的个数,

题目分析:

当把回文串开头和结尾固定为2后,中间部分就是对12-2-2=8进行分解(旦要求8的分解开头和结尾至少为2),也就说12的部分分解包含了8的部分分解。因此本题满足最优子结构性质。
(2)如前所述,12的部分单调回文分解数量包含了8的部分单调回文分解数量。同样,16的单调回文分解中,固定开头和结尾为4后,中间部分就是16-4-4=8进行分解,因此,16的部分单调回文分解数量也包含了8的部分单调回文分解数量。所以,本题满足子问题重叠性质。
设用sequence[n]i表示将n分解成单调回文串中,最左边的整数为i的回文串个数,例如sequence[12[2]表示将12分解成单调口文串中最左边的数为2的个数,它的值等于以下各项之和(本应是7项之和,但只有以下3项不为0)
1)sequence[12-2*2][2]:已经将12分解成了2..2这种形式,所以这项表示将8分解成单调回文串中最左边的数为2的个数,
(2)sequence[12-2*2][4]:这项表示将8分解成单调回文串中最左边的数为4的个数;
(3)sequence[12-2*2][8]:这项表示将8分解成单调回文串中最左边的数为8的个数。
接下来就是求sequence[i]],i>j。易知:
(1)sequence[il[i]=1;
(2)如果i为偶数,则sequence[i][i/2]=1。
(3)1~4行其他非0值:sequence[2][1]=1,sequence[3][1]=1,sequence[4][1]=2,sequence[4][2]= 1。
(4)递推式:当i5时,sequencelill = sequenceli-2*j] + sequenceli-2*j]j+1]+ ... + sequence[i-2*j]lm], m≤i-2*j.
下图给出了求得的sequence数组部分元素的值,

代码:

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n=1;

        while(true) {
            n =scan.nextInt();
            if(n==0) {
                break;
            }
            int x[][]=new int[n+1][n+1];
            for(int i=1;i<=n;i++) {
                x[i][i]=1;
                if(i%2==0) {
                    x[i][i/2]=1;
                }
            }
            x[2][1]=1;

            for(int i=3;i<=n;i++) {
                for(int j=1;i-2*j>=j;j++){
                    for(int k=j;k<=i-2*j;k++) {
                        x[i][j]+=x[i-2*j][k];
                    }

                }

            }
            long sum=0;
            for(int t=1;t<=n;t++) {

                sum+=x[n][t];
            }

            System.out.println(n+" "+sum);

        }

        scan.close();
    }
}
  • 45
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值