어느날 우리애가 풀어보라면 들고 왔습니다. 선생님이 내줬다는 문제인데요....
과연 풀려면 어떻게 할까 생각해보다가, 오랜만에 PC로 풀어볼려고 마음먹었습니다. 정리하자면 아래와 같은 문제입니다.
문제) 1~9까지 서로 다른 숫자를 사용해 들어갈 숫자를 완성하세요.
A B
X C
--------
D E
+ F G
--------
H I
이중에 힌트로 B=7,I=3가 주어졌다고 합니다.
힌트 없이 풀어보도록 하겠습니다.
각각의 값은 중복이 되지 않으므로 순열이라고 보면됩니다.
방법은 A=1...9까지 선택하고 B=1....9 까지 선택하고... 이런식으로 I까지 선택한 후 이전에 선택된 값이라면 무시하고 식이 맞는지 확인하는 방법으로 구해보았습니다.
여러개의 루프를 사용하면서 안쪽에서 다시 루프를 사용하고 아래와 같은 코드에 의해 이미 선택된 값이라면 선택이 되지 않도록 합니다.
if(usedflag[b])continue;
여러개의 루프를 사용하는 방법:
package testProject; public class Test3 { public static void main(String[] args) { test1(); } private static void test1() { boolean usedflag[]={false,false,false,false,false,false,false,false,false,false}; for(int a=1;a<=9;a++){ usedflag[a]=true; for(int b=1;b<=9;b++){ if(usedflag[b])continue; usedflag[b]=true; for(int c=1;c<=9;c++){ if(usedflag[c])continue; usedflag[c]=true; for(int d=1;d<=9;d++){ if(usedflag[d])continue; usedflag[d]=true; for(int e=1;e<=9;e++){ if(usedflag[e])continue; usedflag[e]=true; for(int f=1;f<=9;f++){ if(usedflag[f])continue; usedflag[f]=true; for(int g=1;g<=9;g++){ if(usedflag[g])continue; usedflag[g]=true; for(int h=1;h<=9;h++){ if(usedflag[h])continue; usedflag[h]=true; for(int i=1;i<=9;i++){ if(usedflag[i])continue; usedflag[i]=true; if(((a*10+b)*c)==((d*10)+e)){ if(((d*10)+e)+((f*10)+g)==(h*10)+i){ System.out.println("a="+a+",b="+b+",c="+c+",d="+d+",e="+e+",f="+f+",g="+g+",h="+h+",i="+i); } } usedflag[i]=false; } usedflag[h]=false; } usedflag[g]=false; } usedflag[f]=false; } usedflag[e]=false; } usedflag[d]=false; } usedflag[c]=false; } usedflag[b]=false; } usedflag[a]=false; } } }
결과:
a=1,b=7,c=4,d=6,e=8,f=2,g=5,h=9,i=3
위 방법대로 할경우 문제가 있습니다. 많은 변수를 사용하게 되면 굉장히 코드도 길어지고 그러다보면 실 수 할 수도 있게 됩니다.
그렇다면 코드의 중복되는 부분을 함수로 만들어서 호출해주는 방법을 고민하게 됩니다.
기본적으로 구현은 자기자신을 호출해주는 재귀부와 조건이 맞으면 더이상 재귀를 동작 안하게 하는 두 부분으로 구성됩니다.
재귀부:
for(int i=1;i<=9;i++){ test2(depth+1,usedflag,selected); }더 이상 재귀를 동작 안하게 하는 부분:
if(depth == 9) {
return; }
재귀를 동작 안하게 하려면 얼마나 호출되었는지 관리가 필요합니다. 여기에서는 depth 변수를 이용하여 관리를 하고(자신을 호출시 depth+1 사용) 특정 조건에 맞으면 더 이상의 재귀 동작을 멈추게 합니다. (if(depth==XX) return 조건 사용)
아래는 구현한 내용입니다.
재귀 호출을 이용한 방법:
package testProject; public class Test3 { public static void main(String[] args) { boolean usedflag[]={false,false,false,false,false,false,false,false,false,false}; int selected[]={-1,-1,-1,-1,-1,-1,-1,-1,-1}; test2(0, usedflag, selected); } private static void test2(int depth, boolean usedflag[], int selected[]) { if(depth == 9) { if(((selected[0]*10+selected[1])*selected[2])==((selected[3]*10)+selected[4])){ if(((selected[3]*10)+selected[4])+((selected[5]*10)+selected[6])==(selected[7]*10)+selected[8]){ System.out.println("a="+selected[0]+",b="+selected[1]+",c="+selected[2]+",d="+selected[3]+",e="+selected[4]+",f="+selected[5]+",g="+selected[6]+",h="+selected[7]+",i="+selected[8]); } } return; } for(int i=1;i<=9;i++){ if( usedflag[i] ) continue; usedflag[i]=true; selected[depth]=i; test2(depth+1,usedflag,selected); usedflag[i]=false; } } }
순열에 대한 자세한 내용은 아래 링크를 확인해보세요.
http://swlock.blogspot.kr/2016/11/permutation-combination-algorithm_13.html
댓글 없음:
댓글 쓰기