이 페이지는 코딩도장 데이터의 읽기 전용 정적 보관본입니다.

특이한 계산기

특이한 계산기가 하나 있다.
이 계산기에는 2배 버튼과 리버스 버튼 밖에 없다.

2배 버튼 : 숫자를 두배로 만든다.
리버스 버튼 : 숫자의 제일 앞과 제일 뒷자리수를 바꾼다.
리버스 버튼의 예)
53 -> 35
1234 -> 4231
12345 -> 52341
530 -> 35
5300 -> 305

두 개의 버튼 만으로 1에서 시작해서 77을 만들어 보시오.

추가문제 : 1에서 시작해 757을 만들어 보시오.

2019/05/19 16:17

messi

이 계산기는 모든 자연수에 도달할 수가 없습니다. 예를 들면 3으로 가는 경로는 없습니다. 77과 757은 경로가 있는 특별한 숫자들입니다. 여기에 적힌 풀이들은 소모적 탐색을 통해 경로를 찾기 때문에, 경로가 없는 숫자를 입력하면 무한루프에 빠지고 맙니다. 문제를 수정해서, 숫자에 대한 경로가 없는 경우도 판단하도록 했으면 좋았을 것입니다. - 김준우, 2020/12/30 14:39

11개의 풀이가 있습니다.

Python 3.7

프로그램 내에서 2배, 리버스의 적용 순에 따라 결과가 다르게 나타날 수도 있겠습니다.

def _progress(num: int):  # num에 대해 2배, 리버스 계산 튜플 반환
    reversed_num = 1
    if num >= 10:
        strnum = str(num)
        strnum = strnum[-1] + strnum[1:-1] + strnum[0]
        reversed_num = int(strnum)
    return num * 2, reversed_num


def _find_routes(target: int):
    routes = {1: ""}
    while target not in routes:  # 목표 정수가 routes에 없을 경우
        tmpdic = {}
        for k in routes:  # routes 내 키(정수)에 대해 2배, 리버스 수행
            dbl, swp = _progress(k)
            if dbl not in routes and dbl not in tmpdic:
                tmpdic[dbl] = routes[k] + "D"
            if swp not in routes and swp not in tmpdic:
                tmpdic[swp] = routes[k] + "R"
        routes.update(tmpdic)  # 중복 키를 제외한 사전을 추가하여 routes 갱신
    return routes[target]


def get_routes(target):  # 1 -> num까지 도달하는 과정 출력
    routes = _find_routes(target)
    result = [1]
    for c in routes:
        # 'D': 2배, 'R': 리버스
        addval = result[-1] * 2 if c == "D" else _progress(result[-1])[1]
        result.append(addval)
    return "->".join(str(i) for i in result)


def main():
    result = get_routes(77)
    print(result)
    result = get_routes(757)
    print(result)


if __name__ == "__main__":
    main()

1->2->4->8->16->32->64->128->256->652->1304->2608->5216->6215->12430->24860->49720->9724->19448->38896->77792->27797->55594->45595->91190->1199->9191->18382->28381->56762->26765->53530->3535->7070->77

1->2->4->8->16->61->122->244->488->976->679->1358->8351->16702->26701->53402->106804->213608->427216->627214->1254428->2508856->5017712->2017715->4035430->35434->45433->90866->181732->281731->563462->263465->526930->26935->53870->3875->7750->757

2019/05/24 13:26

mohenjo

python 3.6

def dict_generator(key, value, width=5):
    if key % 10 == 0:
        return {key//2: value+'D'}
    else:
        temp_dict = {}
        if key % 2 == 0:
            temp1 = key//2
            temp_dict[temp1] = value+'D'
        for i in range(width):
            temp2 = '0'*i + str(key)
            temp2 = int(temp2[-1]+temp2[1:-1]+temp2[0])
            temp_dict[temp2] = value+'R'
        return temp_dict


def check_dict(dict, depth=1, max_depth=100, num_limit=100000000):
    print(depth)
    print(list(dict.keys())[-1], list(dict.values())[-1])
    if 1 in dict:
        return dict[1][::-1]
    if depth == max_depth:
        return None
    else:
        temp_dict = {}
        for key, value in dict.items():
            if value[-3:] != 'RRR':
                temp_dict.update(dict_generator(key, value))
        temp_dict = {k: v for k, v in temp_dict.items() if k not in dict.keys() and k < num_limit}
        return check_dict(temp_dict, depth+1)


print(check_dict(dict_generator(77, '')))

77의 경우 'DDDDDDDRDRDRDDDDDRRDDDRDDRDRDRDRDR' 입니다.

757의 경우 'DDDDRDDDDRDRDRDDDDRDDDRDRRDDRDRDRDRDR' 입니다.

width, max_depth, num_limit의 경우 충분히 큰 숫자를 넣어주었습니다.

2019/05/22 20:58

최상혁

#include<cstdio>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
int memory[10000000];
int num_lenght(int num) {
    int temp=1;
    while (temp && num/temp > 10)
    {
        temp*=10;
    }
    return temp;
}

void main()
{
    int n;
    cin >> n;
    queue<int> q;
    q.push(1);
    memory[1] = 1;
    while (!q.empty() && !memory[n])
    {
        int temp = q.front();
        q.pop();

        if (temp * 2 < 10000000 && !memory[temp*2] )
        {
            memory[temp*2] = temp;
            q.push(temp * 2);
        }
        int temp_num = 
            temp % num_lenght(temp) 
            - temp % 10
            + temp / num_lenght(temp)
            + temp % 10 * num_lenght(temp);
        if (temp_num < 10000000 && !memory[temp_num])
        {
            memory[temp_num] = temp;
            q.push(temp_num);
        }
    }
    stack<int> s;
    int temp=n;
    while (temp != 1)
    {
        s.push(temp);
        temp = memory[temp];
    }
    cout << 1 << "\t";
    while (!s.empty()) {
        cout << s.top()<<"\t";
        s.pop();
    }
}

1 2 4 8 16 32 64 128 256 652 1304 2608 8602 17204 34408 68816 137632 275264 550528 850525 1701050 701051 101057 71060 1067 770 77

1 2 4 8 16 61 122 244 488 976 679 1358 8351 16702 26701 53402 106804 213608 427216 627214 1254428 2508856 5017712 2017715 4035430 35434 45433 90866 181732 281731 563462 263465 526930 1053860 53870 107740 7750 757

2019/05/29 21:33

최세진

include

include

include

include

using namespace std; int memory[10000000]; int num_lenght(int num) { int temp=1; while (temp && num/temp > 10) { temp*=10; } return temp; }

void main() { int n; cin >> n; queue q; q.push(1); memory[1] = 1; while (!q.empty() && !memory[n]) { int temp = q.front(); q.pop();

    if (temp * 2 < 10000000 && !memory[temp*2] )
    {
        memory[temp*2] = temp;
        q.push(temp * 2);
    }
    int temp_num = 
        temp % num_lenght(temp) 
        - temp % 10
        + temp / num_lenght(temp)
        + temp % 10 * num_lenght(temp);
    if (temp_num < 10000000 && !memory[temp_num])
    {
        memory[temp_num] = temp;
        q.push(temp_num);
    }
}
stack<int> s;
int temp=n;
while (temp != 1)
{
    s.push(temp);
    temp = memory[temp];
}
cout << 1 << "\t";
while (!s.empty()) {
    cout << s.top()<<"\t";
    s.pop();
}

}

2019/06/09 15:23

신동준

mohenjo님꺼 참고해서 만들어봤습니다

'''특이한 계산기가 하나 있다.
이 계산기에는 2배 버튼과 리버스 버튼 밖에 없다.

2배 버튼 : 숫자를 두배로 만든다.
리버스 버튼 : 숫자의 제일 앞과 제일 뒷자리수를 바꾼다.
리버스 버튼의 예)
53 -> 35
1234 -> 4231
12345 -> 52341
530 -> 35
5300 -> 305

두 개의 버튼 만으로 1에서 시작해서 77을 만들어 보시오.

추가문제 : 1에서 시작해 757을 만들어 보시오.'''
from collections import *
from time import *
def revers_button(number): #리버스 버튼 : 숫자의 제일 앞과 제일 뒷자리수를 바꾼다.
    num=list(str(number))
    num2 = ''
    if len(num)<2:
        for i in num:
            num2 += str(i)
        return int(num2)
    num[0],num[-1]=num[-1],num[0]
    for i in num:
        num2+=str(i)
    return int(num2)


def double_button(number): #두배 버튼
    return int(number*2)

def auto_process(N):

    routes={1:""}
    while N not in routes:
        dic = {}
        for number in routes:
            if double_button(number)  not in dic :
                dic[double_button(number)]=routes[number]+'D'

            if revers_button(number)  not in dic :

                dic[revers_button(number)]=routes[number]+'R'
        routes.update(dic)
    return routes
def auto_button(N):
    print('연산중...')
    pro=auto_process(N)
    print('정답: {}'.format(pro[N]))





while True:
    N=int(input('목표치: '))
    number = 1

    while True:

        print('------------------------------')
        print('1. 두배')
        print('2. 리버스')
        print('3. 정답')
        print('4. 종료')
        print('------------------------------')

        menu=input("버튼을 고르시오 (현재{0},목표{1}): ".format(number,N))

        if menu=='1':
            number=double_button(number)
        elif menu=='2':
            number=revers_button(number)
        elif menu=='3':
            auto_button(N)
            break
        elif menu=='4':
            break
        if number==N:
            print('Clear!!')
            break

    menu2=input('종료 하시겠습니까?y/n: ')
    if menu2=='n':
        continue
    else:
        break

2019/07/10 20:13

정환용

C#

class Program
    {
        static int Twice(int a)
        {
            return a * 2;
        }

        static int Revers(int b)
        {
            string str = b.ToString();
            char[] str_s = str.ToCharArray();
            string rev_str = "";

            if (str.Length == 1)
                return b;

            rev_str = str_s[str.Length - 1].ToString();
            for (int i = 1; i < str.Length - 1; i++)
            {
                rev_str = rev_str + str_s[i].ToString();
            }
            rev_str = rev_str + str_s[0].ToString();

            return int.Parse(rev_str);
        }

        static void Main(string[] args)
        {
            int target = 0;
            int b = 1;
            Random r = new Random();
            string step = "";

            Console.Write("target number : ");
            target = int.Parse(Console.ReadLine());

            while (b != target)
            {
                if (r.Next(0,2) == 0)
                {
                    b = Twice(b);
                    step = step + "T" + b.ToString() + " ";
                } else
                {
                    b = Revers(b);
                    step = step + "R" + b.ToString() + " ";
                }

                if (b > 10000000)
                {
                    b = 1;
                    step = "";
                }
            }
            Console.WriteLine("SUCCESS!!");
            Console.WriteLine(step);
        }
    }

2019/08/21 11:12

류원형

아직 전체 탐색에 대해서도 깊게 공부하지 못한 초보라, 나름 궁리한 것이 리스트를 이용한 탐색이었는데, 조악하기도 하고 시간이 너무 오래 걸려 답이 나올 생각을 하지 않습니다. 코드는 아래와 같습니다.

def CAL(res, path) :
    RES1, rin, path_1, dou, rev = [], [], [], 0, 0
    for i in res :

        dou = i*2

        if not dou in RES1 :
            if dou in res :
                RES1.append(dou)
                path_1.append(path[res.index(dou)])

            else :
                RES1.append(i*2)
                path_1.append(path[res.index(i)] + "D")

        pos_lin = str(i)
        if len(pos_lin) == 1 :
            pos_lin = pos_lin
        else :
            pos_lin = int(pos_lin[-1]+pos_lin[1:-1]+pos_lin[0])

        if not pos_lin in RES1 :

            if pos_lin in res :
                RES1.append(pos_lin)
                path_1.append(path[res.index(pos_lin)])
            else : 
                RES1.append(pos_lin)
                path_1.append(path[res.index(i)] + "R")
    return RES1, path_1

def REP(g, p, c) :
    a, b = CAL(g, p)
    if 77 in a :
        print(b[a.index(77)], a.index(77))
    else :
        return REP(a, b, c+1)

REP([1], [''], 0)

중간 과정을 출력하도록 해서 다른 분들이 올린 코드의 출력들과 비교해 봤는데, 출력이 같거나 비슷한 걸로 봐서는 계산 자체가 틀린 것 같지는 않고, 제 코드가 너무 비효율적이라는 판단에 도달했습니다. 사실 리스트로 코드를 짠 이유도 단순히 딕셔너리 자료형에 익숙하지 않았던 탓이 있었는데, 공부를 게을리 한 결과가 나타난 것 같네요. 그래서 mohenjo님의 코드를 보면서(송구스럽게도 거의 그대로 옮겨놓은 수준입니다.) 딕셔너리 자료형을 활용하여 만들어본 것이 아래 코드인데, 답이 아주 빠르게 구해졌습니다.

def rev(r) :
    if r < 10 :
        return r
    else :
        r = str(r)
        return int(r[-1]+r[1:-1]+r[0])

def cal(res, ob) :
    while not ob in res :
        pre_res = {}
        for n in res :
            rev_n, doub_n = rev(n), 2 * n
            if not rev_n in res :
                pre_res[rev_n] = res[n] + 'R'
            if not doub_n in res :
                pre_res[doub_n] = res[n] + "D"
        res.update(pre_res)
    return ob, res[ob]


RES = {1 : ''}
OBJ = 77
print(cal(RES, OBJ))

결과

(77, 'DDDDDDDDRDDDRDDDRDDDRDRDRRDRDRDRDR')

아래는 위의 계산이 맞는지 확인하기 위해서 1부터 계산을 해본 결과입니다.

- 2 - 4 - 8 - 16 - 32 - 64 - 128 - 256 - 652 - 1304 - 2608 - 5216 - 6215 - 12430 - 24860 - 49720 - 9724 - 19448 - 38896 - 77792 - 27797 - 55594 - 45595 - 91190 - 1199 - 9191 - 18382 - 28381 - 56762 - 26765 - 53530 - 3535 - 7070 - 77

2019/12/26 14:57

GG

Python 3.7.4에서 작성했습니다

class Calculator :
    def __init__(self) :
        self.__list = {}
        self.__current = {1 : ''}

    def double(self, num) :
        return num * 2

    def reverse(self, num) :
        num = str(num)
        return int(num[len(num) - 1] + num[1:len(num) - 1] + num[0])

    def calculate(self, dest) :
        while True :
            self.__temp = {}
            for current in self.__current :
                self.__temp[self.double(current)] = self.__current[current] + 'D'
                if current > 9 :
                    self.__temp[self.reverse(current)] = self.__current[current] + 'R'

            self.__current = self.__temp
            self.__temp.update(self.__list)
            self.__list = self.__temp

            if dest in self.__current :
                print(f"{dest} is Calculated to {self.__current[dest]}")
                return

reverse_calculator = Calculator()
reverse_calculator.calculate(77)
reverse_calculator.calculate(757)

77은 DDDDDDDRDRDRDDDDDRRDDDRDDRDRDRDRDR

757은 DDDDRDDDDRDRDRDDDDRDDDRDRRDDRDRDRDRDR 입니다

2020/02/28 16:32

무안

77일 때는 DDDDDDDDRDDDRDDDRDDDRDRDRRDRDRDRDR,

757일 때는 DDDDRDDDDRDRDRDDDDRDDDRDRRDDRDRDRDRDR,

그리고 무한루프에 빠지지 않도록, 스텝 수에 한도를 두었습니다.

-> 3일 떄는 Steps tried exceeds 40 - given up. 을 출력

경로가 있는지 없는지를 체크하는 것은 대수학 고수께 부탁해야 되겠어요.

워낙 계산량이 많아서 ReverseNum을 최대한 효율적으로 짰습니다.

def ReverseNum(num):
    tens = 1
    while num>10*tens:
        tens *= 10
    a = int(num/tens)
    z = num%10
    return num+(z-a)*tens+a-z

def SeekPath(numTo,numGiveup):
    global SetVisited, DictToVisit
    numTried = 0
    while numTried<numGiveup:
        numTried += 1
        for num in DictToVisit.copy():
            # check if goal reached
            if num==numTo:
                return DictToVisit[num]
            # retrieve path so far
            path= DictToVisit[num]
            # add Double step
            numNext = 2*num
            if numNext not in SetVisited:
                DictToVisit[numNext] = path+'D'
                SetVisited.add(numNext)
            # add Reverse step
            numNext = ReverseNum(num)
            if numNext not in SetVisited:
                DictToVisit[numNext] = path+'R'
                SetVisited.add(numNext)
            # remove num from DictToVisit
            DictToVisit.pop(num)
    return "Steps tried exceeds "+str(numGiveup)+" - given up."

SetVisited = {1}
DictToVisit = {1:""}
print(SeekPath(77,40))

2020/12/30 18:38

김준우

using System;
using System.Collections.Generic;

namespace solution
{
    class Program
    {
        static void Main(string[] args)
        {
            //int N = 77;
            int N = 757;

            var ans = unusualCalculator(N);
            decimal su = 1;
            Console.Write("\n1");
            for (int i = 0; i < ans.Length; i++)
            {
                if (ans[i] == 'D')
                {
                    su *= 2;                    
                }
                else
                {
                    su = reverse(su);
                }
                Console.Write("=>{0}", su);
            }

            Console.WriteLine("\n===============");
        }

        private static string unusualCalculator(int N)
        {
            Dictionary<decimal, string> dic = new Dictionary<decimal, string>();
            dic[1] = "";
            Queue<decimal> que = new Queue<decimal>();
            que.Enqueue(1);
            decimal curr = 1;
            while (true)
            {
                curr = que.Dequeue();
                decimal dSu = curr * 2;
                if (!dic.ContainsKey(dSu)) 
                {
                    dic[dSu] = dic[curr] + "D";
                    que.Enqueue(dSu);
                    if (dSu == N)
                        break;
                }
                if(curr > 10)
                {
                    dSu = reverse(curr);
                    if (!dic.ContainsKey(dSu))
                    {
                        dic[dSu] = dic[curr] + "R";
                        que.Enqueue(dSu);
                    }
                    if (dSu == N)
                        break;
                }
            }
            return dic[N];
        }

        private static decimal reverse(decimal num)
        {
            string str = "";
            str = num.ToString();
            string tmp = "" + str[str.Length - 1];
            for (int i = 1; i < str.Length - 1; i++)
                tmp += str[i];
            tmp += str[0];
            return Convert.ToDecimal(tmp);
        }
    }
}

2023/08/10 13:36

insperChoi

이런 느낌이 맞는 지 모르겠지만 제 생각대로 만들어봤답니다

package free;

// 정수를 입력받아서 거꾸로바꿀지, 제곱을 할지, 그만할지 선택하는 프로그램
import java.util.Scanner;

public class test2 {
    // 스캐너 생성
    public static Scanner sc;

    public static void main(String[] args) {
        sc = new Scanner(System.in);
        // 안내문 출력
        System.out.print("정수 입력 : ");
        // 입력받은 값을 num에 저장
        int num = sc.nextInt();
        // 무슨 행동을 할지 저장하는 n1변수 생성(reverse, square, stop)
        int n1 = 0;
        // n1 != 3 즉 stop을 할때까지 반복하는 반복문이다
        while (n1 != 3) {
            // 안내문 출력
            System.out.print("reverse = 1, square = 2, stop = 3 : ");
            // 행동 값 저장
            n1 = sc.nextInt();
            if (n1 < 1 && n1 > 3) {
                System.out.print("다시 입력하세요 : ");
                n1 = sc.nextInt();
            }
            // 첫 번째 즉 reverse이라면
            if (n1 == 1) {
                // 거꾸로 바꿔주는 코드 실행한뒤
                int p = num;
                int rd;
                int r = 0;
                while (p > 0) {
                    rd = p % 10;
                    r = r * 10 + rd;
                    p = p / 10;
                }
                // num에 초기화 해준다
                num = r;
                // 두 번째 즉 square라면 제곱해준다
            } else {
                num *= 2;
            }
            // 현재 값 출력
            System.out.println("현재 값 : " + num);
            // 받은 값이 1미만 3 초과라면 다시 입력받는다
            // 세 번째를 써주지 않는 이유는 while 조건에서 이미 3을 걸러냈기 때문에 필요가 없다
        }
        // 결과값 출력
        System.out.println("최종값은 " + num + "입니다.");
    }
}

2024/05/23 12:10

최영빈

목록으로