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

경우의 수

다음과 같은 조건을 갖는 상황에서 n개의 계단을 오르는 경우의 수와 각 경우의 내용을 구하는 알고리즘을 C로 프로그램하시오. 순환문을 사용하여 해결하시오.

⑴ 입력 : 임의의 자연수 n

⑵ 조건 : 계단을 오르는 사람이 오른발을 다쳐서 다음과 같은 제한이 있음

  • 왼발은 한번에 1개, 2개, 3개의 계단까지 오를 수 있음.

  • 오른발은 한번에 0개, 1개의 계단까지밖에 오를 수 없음.

  • 연달아서 같은 발을 사용할 수 없음.

⑶ 출력 : 경우의 수와 계단 갯수 순서

n이 2라면

  • 2(왼),

  • 1(왼), 1(오),

  • 1(왼), 0(오), 1(왼),

  • 1(오), 1(왼),

  • 0(오), 2(왼),

  • 0(오), 1(왼), 1(오),

  • 0(오), 1(왼), 0(오), 1(왼),

총 7가지 경우

피보나치 수열

2019/09/25 15:45

eunhyu tb

7개의 풀이가 있습니다.

d[i] = i번째 계단을 왼발로 밟아서 끝나는 경우의 수 i번째 계단을 오른발로 밟고 끝나는 경우의 수는 d[i-1]이므로 d[i]만 계산해놓으면 됩니다.

d[i] = d[i-1] (오른발0칸 + 왼발1칸) + d[i-2] (오른발0칸 + 왼발2칸) + d[i-3] (오른발0칸 + 왼발3칸) +d[i-2] (오른발1칸 + 왼발1칸) + d[i-3] (오른발1칸 + 왼발2칸) + d[i-4] (오른발1칸 + 왼발3칸)

이므로, 이 점화식을 잘 계산하면 됩니다. 답은 d[n] + d[n-1]이 됩니다.

C++은 긴자리수에 대한 표현이 영 안좋아서 n=52일 때에 대한 답을 구하는게 최선인데 만약 긴자리수를 아주 편하게 쓸 수 있는 python이나 JAVA같은 친구들을 사용하면 n=50,000 정도까지는 의미있는 시간 내에 계산할 수 있지 않을까 싶습니다. 물론 아래 코드로 구현한 O(n)짜리 보통의 방법으론 안되고 행렬의 제곱으로 푸는 O(log n)짜리를 사용해서 겨우겨우...

#include<stdio.h>
int n;
unsigned long long int d[1009];
int main()
{
    int i, j, k;
    scanf("%d", &n);
    if (n>52) { printf("Too Big!\n"); }
    d[0] = 1;
    d[1] = 2;
    d[2] = 5;
    d[3] = 12;
    for (i = 4; i <= n; i++) {
        d[i] = d[i - 1] + 2 * d[i - 2] + 2 * d[i - 3] + d[i - 4];
    }
    printf("%llu\n", d[n] + d[n-1]);
}

2019/09/26 23:51

pichulia

Python 3.7

pichulia님 코드를 참고해서 python으로 구현했습니다.

def sta(n):
    a = [1, 2, 5, 12] + [0]*(n-3)
    i = 4
    while i <= n:
        a[i] = a[i-1] + 2*a[i-2] + 2*a[i-3] + a[i-4]
        a[i-4] = 0
        i += 1
    return a[n]+a[n-1]

a[i-4] = 0 부분은 큰 수 계산을 위해서 넣었습니다. 넣지 않았을 경우 sta(200000)을 계산할 때 메모리를 3기가 먹습니다. 공간복잡도 O(n2)

아래는 리스트 대신 변수를 사용한 식입니다.

def sta(n):
    if n < 4:
        a = [1, 2, 5, 12]
        return a[n]+a[n-1]
    a, b, c, d = 12, 5, 2, 1
    i = 4
    while i <= n:
        a, b, c, d = a + 2*b + 2*c + d, a, b, c
        i += 1
    return a + b

계산은 sta(100000) = 1.3초, sta(200000) = 5.5초, sta(400000) = 22초 정도 걸립니다.(cpu 성능에 따라 다릅니다.)

이 코드들은 루프가 1개라서 O(n)처럼 보이지만, n이 2배 증가할 때 연산값의 자릿수(log)가 2배씩 증가하여 실제 시간복잡도는 O(n2)이 됩니다.

2019/10/02 16:12

AY

def stair(n):
    START, LEFT, RIGHT = 'Start', 'Left', 'Right'
    que = [[(0, START, 0)]]
    cnt = 0

    while que:
        seq = que.pop(0)
        stride, foot, pos = seq[-1] # last step

        if n < pos:
            continue

        if n == pos:
            print([step[:2] for step in seq[1:]])
            cnt += 1
            continue

        if foot in (START, LEFT):
            que.append(seq + [(0, RIGHT, pos + 0)])
            que.append(seq + [(1, RIGHT, pos + 1)])

        if foot in (START, RIGHT):
            que.append(seq + [(1, LEFT, pos + 1)])
            que.append(seq + [(2, LEFT, pos + 2)])
            que.append(seq + [(2, LEFT, pos + 3)])

    print(cnt)

2019/09/26 15:06

Noname

C 재귀함수를 이용하여 작성해보았습니다.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

unsigned long long int advance(int n, int curr, bool leftFoot);

int main() {
    int n;

    printf("n을 입력하세요: ");
    scanf("%d", &n);

    printf("경우의 수: %llu", advance(n, 0, true) + advance(n, 0, false));

    return 0;
}

unsigned long long int advance(int n, int curr, bool leftFoot) {
    // 맨 밑일 때 curr == 0, 도착하는 순간 curr == n

    // 현재 위치가 n보다 큰 경우 유효하지 않은 움직임
    if (curr > n) {
        return 0;
    }

    // 현재 위치가 n과 같은 경우 성공적인 경우의 수 중 하나
    if (curr == n) {
        return 1;
    }

    unsigned long long int result = 0; // 최종 return되는 경우의 수

    if (leftFoot == true) {
        // 왼발로 오름
        result += advance(n, curr + 1, false);
        result += advance(n, curr + 2, false);
        result += advance(n, curr + 3, false);
    }
    else {
        // 오른발로 오름
        result += advance(n, curr, true);
        result += advance(n, curr + 1, true);
    }

    return result;
}

2020/07/15 18:28

구루마

ㅎㅎ 재미있네요. 요구사항대로 그냥 C 언어입니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int     N_Case=0;

void limp(char *sSteps, char cLastStep, int n_todo) {
int     i;
char    *sNextSteps;
        if (n_todo==0) {
                printf("%s\n", sSteps);
                ++N_Case;
        }
        if (n_todo<=0)
                return;
        sNextSteps = (char*)malloc(strlen(sSteps)+3);
        if (cLastStep!='L')
                for (i=1; i<=3; i++) {
                        sprintf(sNextSteps,"%s L%d", sSteps, i);
                        limp(sNextSteps, 'L', n_todo-i);
                }
        if (cLastStep!='R')
                for (i=0; i<=1; i++) {
                        sprintf(sNextSteps,"%s R%d", sSteps, i);
                        limp(sNextSteps, 'R', n_todo-i);
                }
        free(sNextSteps);
}

int main() {
int     n;
        printf("Number (>0) ? ");
        scanf("%d", &n);
        limp("", ' ', n);
        printf("%d cases.\n", N_Case);
}

2020/12/08 17:06

김준우

파이썬으로도 해보았습니다..

def Limp(steps, laststep, n_todo):
    global Case
    if (n_todo==0):
        print(steps)
        Case = Case+1
    if (n_todo<=0):
        return
    if (laststep!='왼'):
        for left in range(1,4):
            next_steps = steps.copy()
            next_steps.append('왼'+str(left))
            Limp(next_steps, '왼', n_todo-left)
    if (laststep!='오'):
        for right in range(0,2):
            next_steps = steps.copy()
            next_steps.append('오'+str(right))
            Limp(next_steps, '오', n_todo-right)

N = int(input('자연수: '))
Case = 0
Limp([],' ',N)
print("총", Case, "경우")

2020/12/08 17:16

김준우

using System;
using System.Collections.Generic;

namespace solution2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("\n  임의의 자연수 n을 입력하세요: ");
            int n = int.Parse(Console.ReadLine());
            List<string> caselist = new List<string>();
            numOfCases(0, "right", n, "", caselist);
            numOfCases(0, "left", n, "", caselist);

            foreach (var c in caselist)
            {
                Console.WriteLine(c);
            }
            Console.WriteLine("\n  {0}", caselist.Count);
        }

        private static void numOfCases(int s, string foot, int n, string step, List<string> caselist)
        {
            if (s == n)
            {
                caselist.Add(step);
                return;
            }

            if (s > n)
                return;

            if (foot == "right")
            {
                for (int i = 0; i <= 1; i++)
                    numOfCases(s + i, "left", n, step+i+"(오)" + ",", caselist);
            }
            else
            {
                for (int i = 1; i <= 3; i++)
                    numOfCases(s + i, "right", n, step +i + "(왼)" + ",", caselist);
            }
        }
    }
}

2023/07/25 20:46

insperChoi

목록으로