Prime+Cryptarithm

Prime Cryptarithm
The following cryptarithm is a multiplication problem that can be solved by substituting digits from a specified set of N digits into the positions marked with *. If the set of prime digits {2,3,5,7} is selected, the cryptarithm is called a PRIME CRYPTARITHM.



x * *

---


 * * * <-- partial product 1


 * * * <-- partial product 2

---



Digits can appear only in places marked by `*'. Of course, leading zeroes are not allowed.

Note that the 'partial products' are as taught in USA schools. The first partial product is the product of the final digit of the second number and the top number. The second partial product is the product of the first digit of the second number and the top number.

Write a program that will find all solutions to the cryptarithm above for any subset of digits from the set {1,2,3,4,5,6,7,8,9}.

PROGRAM NAME: crypt1

INPUT FORMAT

Line 1: N, the number of digits that will be used

Line 2: N space separated digits with which to solve the cryptarithm

SAMPLE INPUT (file crypt1.in)

5

2 3 4 6 8

OUTPUT FORMAT

A single line with the total number of unique solutions. Here is the single solution for the sample input:

2 2 2

x 2 2

--

4 4 4

4 4 4

-

4 8 8 4

SAMPLE OUTPUT (file crypt1.out)

1

Source Code code format="java" /* ID: wjh3331 LANG: JAVA TASK: crypt1 */

import java.io.*; import java.util.StringTokenizer;

public class crypt1 { public static final int MAX = 10000;

public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new FileReader("crypt1.in")); PrintWriter out = new PrintWriter(new FileWriter("crypt1.out"));

int n = Integer.parseInt(in.readLine); // 원소의 개수 StringTokenizer st = new StringTokenizer(in.readLine);

int[] set = new int[n]; // 곱셈 과정을 구성할 집합 for (int i = 0; i < n; i++) { set[i] = Integer.parseInt(st.nextToken); }

// 미리 나올 수 있는 경우의 수를 다 체크함. boolean[] subset = new boolean[MAX];

for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { subset[set[i] * 100 + set[j] * 10 + set[k]] = true;

for (int l = 0; l < n; l++) { subset[set[i] * 1000 + set[j] * 100 + set[k] * 10 + set[l]] = true; }       }      }    }

// 수를 바꿔가며 곱셈을 하여 조건에 맞는 곱셈 과정의 수를 구함 int count = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { // 곱셈 시작 int a = set[i] * 100 + set[j] * 10 + set[k];

for (int l = 0; l < n; l++) { // 곱셈 과정의 세번째 수를 판단 int b = a * set[l]; if (b > 999) { continue; }           if (!subset[b]) { continue; }

for (int m = 0; m < n; m++) { // 곱셈 과정의 네번째 수를 판단 int c = a * set[m];

if (c > 999) { continue; }             if (!subset[c]) { continue; }

// 곱셈 과정의 마지막 수를 판단 int d = b * 10 + c;

if (d > 9999) { continue; }

if (subset[d]) { count++; }           }          }        }      }    }

// 결과 출력 out.println(count);

out.close; System.exit(0); } } code

Comment 몇가지 방법을 생각해보았습니다. 처음에는 라이브러리의 힘을 빌려 문자열 <--> 숫자로 막바꾸면서 해볼까 라고도 생각해 보았지만 너무 느릴거 같아서 패스... 두번째는 2차원 배열에 곱셈 과정이랑 똑같이 수를 넣는 방법... 이건 캐리 때문에 복잡해져서 패스... 곰곰히 생각해보니 체크할때 숫자를 각 자리로 나누는 연산( /, % )이 대부분의 시간을 잡아먹지 않을까 하는 생각이 들더군요... 그래서 최대한 없애보자라고 생각을 했고 판단 결과를 미리 배열에 저장해놓고 판단하면 좋을 것 같았습니다. 속도를 위해 메소드 호출도 안하려고 했더니 for문이 5개나 겹치네요;; 동적계획법이 이렇게 하는게 맞는건가요? ㄷㄷ 제가 글솜씨가 없어서 설명을 잘 못하겠네요... 죄송;;