算法设计与分析: 5-28 虫蚀算式问题

本文介绍了虫蚀算式问题,即通过剩余数字推断被虫蛀部分,以解决这类问题。文章提供了问题描述,指出通常假设所有数字被蛀,但知道哪些数字相同,并且算式为n进制加法。通过编程实现,利用回溯法来确定虫蚀算式的缺失数字。数据输入包括n进制和三个包含n个大写字母的字符串,代表两个加数和它们的和,相同的字母表示相同数字。

5-28 虫蚀算式问题


问题描述

虫蚀算式是指古书中算式的一部分被虫蛀了。虫蚀算式问题是根据虫蚀算式剩下的数字,逻辑推断被虫蛀了的数字。例如,

43?98650?45+8468?66334444550697843?98650?45+8468?663344445506978

其中“?”表示虫蛀的数字。根据此虫蚀算式,容易推断出,第 1 行的 2 个虫蛀数字分 别是 5 和 3,第 2 行的虫蛀数字是 5。
一般情况下,虫蚀算式问题假设,算式中所有数字都被虫蛀了,但是知道虫蚀算式中哪 些数字相同。另外还知道虫蚀算式是 n 进制加法算式。虫蚀算式中的 3 个数都是 n 位数,且允许前导 0。

对于给定的虫蚀算式,编程计算算式中的虫蚀数字。

数据输入:
第 1 行有 1 个正整数 n(n<=26),表示所给的虫蚀算式是 n 进制加法算式。其后 3 行中,每行有 1 个由 n 个大写英文字母组成的字 符串,分别表示虫蚀算式中的 2 个加数及其和。相同的英文字母代表相同的数字。


Java

package Chapter5HuiSuFa;

import java.util.Scanner;

public class ChongShiSuanShi {

    private static class Node{
        int a,b,c;
        Node next;
    }

    private static int n;
    private static int[][] B;
    private static int[] x;
    private static Node[] cut;

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

        while (true){
            n = input.nextInt();

            B = new int[n][3];
            x = new int[n];
            cut = new Node[n];


            for(int j=0; j<3; j++){
                String a = input.next();
                for(int i=0; i<n; i++)
                    B[i][j] = a.charAt(i)-'A';
            }

            for(int i=0; i<n; i++)
                x[i] = i;

            construct();

            backtrack(0);
        }
    }

    private static boolean backtrack(int i){
        if(i == n-1){
            if(oka()){
                for(int j=0; j<n; j++)
                    System.out.print(x[j]+" ");
                return true;
            }else
                return false;
        }else
            for(int j=i; j<n; j++){
                swap(x,i,j);
                if(constrain(i) && backtrack(i+1))
                    return true;
                swap(x,i,j);
            }

        return false;
    }

    private static void swap(int[] x, int i, int j){
        int tmp = x[i];
        x[i] = x[j];
        x[j] = tmp;
    }

    private static boolean oka(){
        int carr = 0;
        for(int i=n-1; i>=0; i--){
            int sum = x[B[i][0]]+x[B[i][1]]+carr;
            if(sum%n != x[B[i][2]]) return false;
            carr = sum/n;
        }

        return true;
    }

    private static boolean constrain(int i){
        for(int j=0; j<=i; j++){
            if(vio(cut[j]))
                return false;
        }

        return true;
    }

    private static boolean vio(Node p){
        while (p != null){
            if((x[p.a]+x[p.b])%n != x[p.c] && (x[p.a]+x[p.b]+1)%n != x[p.c])
                return true;
            p = p.next;
        }

        return false;
    }

    private static void construct(){
        Node p;
        for(int i=0; i<n; i++)
            cut[i] = null;
        for(int i=0; i<n; i++){
            int maxi = B[i][0];
            for(int j=1; j<3; j++)
                if(maxi < B[i][j])
                    maxi = B[i][j];
            p = new Node();
            p.a = B[i][0];
            p.b = B[i][1];
            p.c = B[i][2];
            p.next = cut[maxi];
            cut[maxi] = p;
        }
    }
}

Input & Output

5
ABCED
BDACE
EBBAA
1 0 3 4 2 



7
BCEFDAG
CABGEDF
GDGFAGG
1 2 4 5 3 0 6 

Reference

王晓东《计算机算法设计与分析》

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值