算法设计与分析: 3-12 圈乘运算问题

博客探讨了圈乘运算问题,定义为X⨂⨂Y等于X的数字之和乘以Y的最大和最小数字。文章提供了两种Java实现,旨在解决如何找到使用最少圈乘运算得到特定值K的算法。内容引用自王晓东的《计算机算法设计与分析》。

3-12 圈乘运算问题


问题描述

关于整数的 2 元圈乘运算定义为
(XY)=10 进制整数 X 的各位数字之和××10进制整数Y 的最大数字++Y的最小数字。 例如,(930)=9*3+0=27。
对于给定的10进制整数X和K,由X和运算可以组成各种不同的表达式。试设计一个算法,计算出由 X 和运算组成的值为 K 的表达式最少需用多少个运算。


Java: version 1

import java.util.Scanner;

public class QuanChengYunSuan {
    private static int kk;
    private static int len;
    private static int big;
    private static int[][] num;

    private static String s1,s2;

    private static int MAX = 100000;

    public static void main(String[] args){
        if(input())
            init();
        else
            return;

        compute();
    }

    private static void compute(){
        boolean flag = true;
        while (flag){
            flag = false;
            for(int i=0; i<big; i++)
                if(num[i][0] < MAX)
                    for(int k=0; k<big; k++)
                        if(num[k][0] < MAX){
                            int j = num[i][3]*num[k][2]+num[k][1];
                            if(num[i][0]+num[k][0]+1 < num[j][0]){
                                num[j][0] = num[i][0]+num[k][0]+1;
                                flag = true;
                            }
                        }
        }
        if(num[kk][0] < MAX)
            out(num[kk][0]);
        else
            out(-1);
    }

    private static boolean input(){
        Scanner input = new Scanner(System.in);

        s1 = input.next();
        s2 = input.next();

        if(s1.equals(s2)){
            out(0);
            return false;
        }

        len = s1.length();
        big = 81*len+9;
        if(big < 171)
            big = 171;

        int biglen = (int)Math.ceil(Math.log10(big));
        if(s2.length() > biglen) {
            out(-1);
            return false;
        }
        kk = Integer.parseInt(s2);
        if(kk > big){
            out(-1);
            return false;
        }

        return true;
    }

    private static int ctoi(char x){
        return (int)x - 48;
    }

    private static void out(int x){
        if(x >= 0)
            System.out.println("The number of X is: "+x);
        else
            System.out.println("No answer!");
    }

    private static void init(){
        num = new int[++big][4];
        for(int i=0; i<big; i++){
            num[i][0] = MAX;
            num[i][1] = MAX;
            num[i][2] = 0;
            num[i][3] = 0;
        }

        for(int i=0; i<len; i++)
            count(ctoi(s1.charAt(i)), 0);

        num[0][0] = 0;

        for(int i=1; i<big; i++){
            int t = i;
            while (t > 0){
                int j = t%10;
                t /= 10;
                count(j, i);
            }
        }
    }

    private static void count(int i, int j){
        if(i < num[j][1])
            num[j][1] = i;
        if(i > num[j][2])
            num[j][2] = i;
        num[j][3] += i;
    }
}

Java: version 2

import java.util.Scanner;

public class QuanChengYunSuan2 {

    public static int kk,len,big,biglen,sum;
    public static int[] leftn;
    public static int[][] rightn;

    public static String s1;
    public static String s2;

    private static int MAX = 1000000;

    public static void main(String[] args){
        if(input())
            init();
        else
            return;

        compute();
    }

    private static void compute(){
        int a, b, c, best = MAX;
        int[] abc = new int[3];
        boolean flag = true;
        while (flag){
            flag = false;
            for(int i=0; i<=biglen; i++)
                if(leftn[i] < MAX)
                    for(int j=0; j<10; j++)
                        for(int k=0; k<=j; k++)
                            if(rightn[k][j] < MAX){
                                int num;
                                if(i > 0)
                                    num = i*j+k;
                                else
                                    num = sum*j+k;

                                trans(num, abc);
//                                a = abc[0];
//                                b = abc[1];
//                                c = abc[2];
                                int curr = leftn[i] + rightn[k][j] + 1;
                                if(curr < leftn[abc[2]]){
                                    leftn[abc[2]] = curr;
                                    flag = true;
                                }
                                if(curr < rightn[abc[0]][abc[1]]){
                                    rightn[abc[0]][abc[1]] = curr;
                                    flag = true;
                                }
                                if(num == kk && curr < best){
                                    best = curr;
                                    flag = true;
                                }
                            }
        }
        if(best < MAX)
            out(best);
        else
            out(-1);
    }

    private static void trans(int t, int[] abc){
        abc[0] = MAX;
        abc[1] = 0;
        abc[2] = 0;
        while (t > 0){
            int j = t%10;
            t /= 10;
            count(j, abc);
        }
    }

    private static boolean input(){
        Scanner input = new Scanner(System.in);

        s1 = input.next();
        s2 = input.next();

        if(s1.equals(s2)){
            out(0);
            return false;
        }

        len = s1.length();
        big = 81*len+9;
        if(big < 171)
            big = 171;

        biglen = (int)Math.ceil(Math.log10(big));
        if(s2.length() > biglen) {
            out(-1);
            return false;
        }
        kk = Integer.parseInt(s2);
        if(kk > big){
            out(-1);
            return false;
        }

        return true;
    }

    private static void init(){
        biglen *= 9;
        rightn = new int[10][10];

        for(int i=0; i<10; i++)
            for(int j=0; j<10; j++)
                rightn[i][j] = MAX;

        leftn = new int[biglen+1];
        for(int i=1; i<=biglen; i++)
            leftn[i] = MAX;

        int a = MAX, b = 0;
        sum=0;
        int[] abc = new int[3];
        abc[0] = a;
        abc[1] = b;
        abc[2] = sum;
        leftn[0]=0;

        for(int i=0; i<len; i++)
            count(ctoi(s1.charAt(i)), abc);

        a = abc[0];
        b = abc[1];
        sum = abc[2];

        rightn[a][b] = 0;
        if(sum <= biglen)
            leftn[sum] = 0;
    }

    private static int ctoi(char x){
        return (int)x - 48;
    }

    private static void out(int x){
        if(x >= 0)
            System.out.println("The number of X is: "+x);
        else
            System.out.println("No answer!");
    }

    private static void count(int i, int[] abc){
        if(i < abc[0])
            abc[0] = i;
        if(i > abc[1])
            abc[1] = i;
        abc[2] += i;
    }
}

Input & Output

3 12
The number of X is: 1

Reference

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值