#include #include #include #include using namespace std; typedef struct {int p,q;} frac; // 분수 자료형 frac op(frac a, frac b, int o){ // 분수끼리의 연산 실행 frac r; switch(o){ case 0: r.p = a.p*b.q+a.q*b.p; r.q = a.q*b.q; break; // a+b case 1: r.p = a.p*b.p; r.q = a.q*b.q; break; // a*b case 2: r.p = a.p*b.q-a.q*b.p; r.q = a.q*b.q; break; // a-b case 3: r.p = a.q*b.p-a.p*b.q; r.q = a.q*b.q; break; // b-a case 4: r.p = a.p*b.q; r.q = b.q==0?0:a.q*b.p; break; // a/b case 5: r.p = a.q*b.p; r.q = a.q==0?0:a.p*b.q; // b/a } return r; } /* operator를 6개 둔 이유? * 이 코드에서 경우의 수를 탐색하는 방법: 5개 중 2개를 골라 연산 실행 -> 4개 중 2개 -> ... * 뺄셈, 나눗셈은 교환법칙이 성립하지 않으므로 a/b와 b/a를 다른 경우로 처리해야 함 * (2+1)*3과 (1+2)*3 같은 경우를 중복해서 세지 않도록 하여 따져보는 경우의 수를 줄임 * 이 코드에서는 같은 수가 있는 경우를 따로 다루지 않아 약간의 차이가 있지만 더 최적화할 수 있음 * 총 경우의 수 (9H5)*(5C2*4C2*3C2*2C2)*(6^4) = 1287*180*(6^4) = 300,231,360 * 최적화를 한다면 60% 수준까지도 줄일 수 있을 것으로 예상 */ int num[5], oper[4]; // iteration을 돌게 될 변수들. 전역변수로 두어 다른 함수에서 활용 bool poss[70000]; // 그 자연수가 가능한지를 나타내는 bool 배열 frac x[5]; // 연산에 사용할 분수들 vector > ans_vec; // 최대로 나타낼 수 있는 수와 그 수를 만드는 숫자들의 정보 저장 int itonums[2003][5], idx = 0; // itonums는 (1,1,1,1,1)~(9,9,9,9,9)를 순서대로 저장하게 된다 // ans_vec의 두 번째 원소를 이용하면 itonums를 통해 5개의 수를 알아낼 수 있다 void init(){ // x[0]~x[4]를 각각 num[0]~num[4]로 초기화 for(int i=0;i<5;i++){ x[i].p=num[i]; x[i].q=1; } } void iter(){ // 5C2 * 4C2 * 3C2 * 2C2 = 180가지 경우를 따져보는 함수 int chng[4][2]; // 바꾸는 2개의 수의 index chng[3][0]=1; chng[3][1]=0; // 마지막 2개는 경우의 수가 단 한 가지임 for(chng[0][0]=1;chng[0][0]<5;chng[0][0]++){ for(chng[0][1]=0;chng[0][1] 0){ // 자연수라면 poss[x[0].p/x[0].q] = 1; // 이 자연수가 가능함을 기록 } } } } } } } } int main(){ for(num[0]=1;num[0]<10;num[0]++){ for(num[1]=num[0];num[1]<10;num[1]++){ for(num[2]=num[1];num[2]<10;num[2]++){ for(num[3]=num[2];num[3]<10;num[3]++){ for(num[4]=num[3];num[4]<10;num[4]++){ // 여기까지가 number setting for(int i=0;i<70000;i++) poss[i]=0; // poss 배열 초기화 for(oper[0]=0;oper[0]<6;oper[0]++){ for(oper[1]=0;oper[1]<6;oper[1]++){ for(oper[2]=0;oper[2]<6;oper[2]++){ for(oper[3]=0;oper[3]<6;oper[3]++){ // 여기까지가 operator setting iter(); } } } } int tmp; // 1부터 시작해서 연속으로 만드는 최대의 수를 저장할 것이다 for(tmp=1;poss[tmp];tmp++); // poss[tmp]가 0이 되는 순간 루프 빠져나옴 for(int i=0;i<5;i++) itonums[idx][i]=num[i]; ans_vec.push_back(make_pair(tmp-1,idx)); // tmp-1까지를 만들 수 있다 idx++; if(idx % 50 == 0){ printf("%d/1287 case complete\n",idx); // 진행도 표시 } } } } } } sort(ans_vec.begin(),ans_vec.end()); // 앞의 원소롤 기준으로 오름차순 정렬, 마지막 원소가 우리가 원하는 답 printf("Maximum possible is %d for (%d, %d, %d, %d, %d)\n",ans_vec[idx-1].first,itonums[ans_vec[idx-1].second][0],itonums[ans_vec[idx-1].second][1], itonums[ans_vec[idx-1].second][2],itonums[ans_vec[idx-1].second][3],itonums[ans_vec[idx-1].second][4]); // 아래 코드는 output.txt에 모든 경우(9H5=1287가지)를 기록함 // 순서는 연속해서 만들 수 있는 최대 수에 대한 내림차순 FILE *f = fopen("output.txt","w"); for(int i=idx-1;i>=0;i--){ fprintf(f,"%d for (%d, %d, %d, %d, %d)\n",ans_vec[i].first,itonums[ans_vec[i].second][0],itonums[ans_vec[i].second][1], itonums[ans_vec[i].second][2],itonums[ans_vec[i].second][3],itonums[ans_vec[i].second][4]); } }