算法设计与分析: 5-36 最短加法链问题

5-36 最短加法链问题


问题描述

最优求幂问题:给定一个正整数n和一个实数x,如何用最少的乘法次数计算出 x n 。 例如,可以用 6 次乘法逐步计算 x 23 如下: x x 2 x 3 x 5 x 10 x 20 x 23 。可以证明 计算 x 23 最少需要 6 次乘法。计算 x 23 的幂序列中各幂次 1,2,3,5,10,20,23 组成了一 个关于整数 23 的加法链。在一般情况下,计算 x n 的幂序列中各幂次组成正整数 n 的一个加法链:

1 = a 0 < a 1 < a 2 < . . . < a r = n

a i = a j + a k , k j < i , i = 1 , 2 , . . . , r

上述最优求幂问题相应于正整数 n 的最短加法链问题,即求 n 的一个加法链使其长度 r 达到最小。正整数n的最短加法链长度记为l(n)。

对于给定的正整数 n ,编程计算相应于正整数 n 的最短加法链。

数据输入:
第 1 行有 1 个正整数 n。


Java

package Chapter5HuiSuFa;

import java.util.Scanner;

public class ZuiDuanJiaFaLian {

    private static int MAXN = 10000;
    private static int n;

    private static int[] chain;
    private static int best;

    private static boolean found;
    private static int lb,ub,t;

    private static int[] a,parent;

    public static void main(String[] args){
        Scanner input = new Scanner(System.in);

        while (true){
            best = MAXN;

            n = input.nextInt();

            chain = new int[MAXN];
            a = new int[MAXN];
            parent = new int[MAXN+1];

            if(n <= MAXN) {search(); output();}
            else System.out.println("Number too large!");
        }
    }

    private static void search(){
        lb = lowerb(n);
        ub = powertree(n);
        t = gett(n);
        if(lb < ub){
            found = false;
            while (!found){
                System.out.println("lb="+lb);
                a[1] = 1;
                backtrack(1);
                lb++;
                if(lb == ub) found=true;
            }
        }
    }

    private static int powertree(int n){
        found = false;
        ub = 1;
        for(int i=1; i<=MAXN; i++) parent[i]=0;
        while (!found){
            a[1] = 1;
            find(1);
            ub++;
        }

        return best;
    }

    private static void find(int step){
        int i,k;
        if(!found)
            if(a[step] == n){
                best = step;
                for(i=1; i<=best; i++) chain[i]=a[i];
                found = true;

                return;
            }else if(step <= ub)
                for(i=1; i<=step; i++){
                    k = a[step]+a[i];
                    if(k <= n){
                        a[step+1] = k;
                        if(parent[k] == 0) parent[k]=a[step];
                        if(parent[k] == a[step]) find(step+1);
                    }
                }
    }

    private static void backtrack(int step){
        if(!found)
            if(a[step] == n){
                best = step;
                for(int i=1; i<=best; i++)
                    chain[i] = a[i];
                found = true;

                return;
            }else if(step < lb)
                for(int i=step; i>=1; i--)
                    if(2*a[i] > a[step])
                        for(int j=i; j>=1; j--){
                            int k = a[i]+a[j];
                            a[step+1] = k;
                            if(k>a[step] && k<=n)
                                if(!pruned(step+1))
                                    backtrack(step+1);
                        }
    }

    private static boolean pruned(int step){
        if(step < lb-t-1) return (h(3*a[step])+step+2 > lb);
        else return (h(a[step])+step > lb);
    }

    private static int h(int num){
        int i=0;
        while (num < n) {num=num<<1; i++;}

        return i;
    }

    private static int lowerb(int m){
        int i=0,j=1;
        while (m > 1) { i++; if(odd(m)) j++; m=m>>1;}
        i += log2(j)+1;

        return i;
    }

    private static int log2(int m){
        int i=0,j=1;
        while (m > 1) {i++; if(odd(m)) j++; m=m>>1;}
        if(j > 1) i++;

        return i;
    }

    private static int gett(int num){
        int i=0;
        while (!odd(num)) {num=num>>1; i++;}

        return i-1;
    }

    private static void output(){
        System.out.println(best-1);
        for(int i=1; i<=best; i++)
            System.out.print(chain[i]+" ");
    }

    private static boolean odd(int num){
        return num%2==1;
    }
}

Input & Output

23
6
1 2 3 5 10 13 23 


25
6
1 2 3 5 10 15 25 

13
5
1 2 3 5 10 13

Reference

王晓东《计算机算法设计与分析》(第3版)P189

猜你喜欢

转载自blog.csdn.net/ioio_/article/details/81156677
今日推荐