반응형

문제 링크

 

9095번: 1, 2, 3 더하기

문제 정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다. 1+1+1+1 1+1+2 1+2+1 2+1+1 2+2 1+3 3+1 정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오. 입력 첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 11보다 작다. 출력 각

www.acmicpc.net

 

이 문제는 두 가지 방법으로 풀어봤다.

풀이 1 ) 완전 탐색

  a1, a2, a3에 각각 1, 2, 3의 개수를 저장한 후 그 3가지의 순서 개수를 구했다. 팩토리얼을 구하는 라이브러리 함수가 없으므로 내가 만들었다. 물론 여기서 팩토리얼을 구할 때 재귀 호출이 아닌 dp를 사용하여 구할 수도 있지만 문제에서 주어진 n의 크기가 작으므로 재귀 호출로 구해주었다.

  단 이 때는 팩토리얼의 크기가 int범위를 벗어나지 않는지 확인해줄 필요가 있다. 12! 까지 int로 표현 가능하고 13! 부터는 long long형을 사용하면 되는데 그냥 long long형을 사용하는 게 더 편한 것 같다.

 

#include <cstdio>
using namespace std;

int fac(int);

int main(void)
{
    int t;
    scanf("%d", &t);
    while(t--){
        int n;
        int ans = 0;
        scanf("%d", &n);

        int a1, a2, a3;
        for(a3 = 0; a3*3 <= n; a3++){
            for(a2 = 0; a3*3 + a2*2 <= n; a2++){
                a1 = n - a3*3- a2*2;
                ans += fac(a1+a2+a3)/fac(a1)/fac(a2)/fac(a3);
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

int fac(int n)
{
    if(n < 2) return 1;
    else return n*fac(n-1);
}

 

풀이 2 ) dp

  n을 1, 2, 3으로 나타내는 방법은 다시 보면 1로 시작하는 경우와 2로 시작하는 경우와 3으로 시작하는 경우 3가지로 나눌 수 있다. 1로 시작하는 경우는 1과 n-1로 나누고 2, 3도 같은 방식으로 나눌 수 있다. 즉  n을 1, 2, 3으로 나타내는 방법의 수를 f(n)이라 했을 때 f(n) = f(n-1) + f(n-2) + f(n-3)으로 나타낼 수 있다.

  위의 식을 재귀로 구할 수도 있지만 dp를 사용하여 구했다.

 

#include <cstdio>
using namespace std;

int memo[12] = {1, 2, 4, };

int main(void)
{
  int t;
  scanf("%d", &t);
  while(t--){
    int n;
    scanf("%d", &n);
    for(int i = 3; i < n; ++i)
      memo[i] = memo[i-1] + memo[i-2] + memo[i-3];
    printf("%d\n", memo[n-1]);
  }
  return 0;
}

 

반응형
반응형

문제 링크

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다. 정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다. 아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누

www.acmicpc.net

 

풀이 ) 완전 탐색

  우선 각 테트로미노 모양을 모두 배열 형태로 만들어 놓는다.

  이 때 모양이 안겹치고 빠뜨리는 게 없도록 조심해야된다. 필자는 여러 번 실수했다.

  그리고 나서는 가장 첫 번째 행 첫 번째 열부터 시작하여 각 모양으로 확인을 한다. 이때 각 행 열이 판에서 벗어나지 않는지 검사를 하여 벗어나는 경우 다음 반복문으로 넘어간다.

 

#include <cstdio>
#include <algorithm>
using namespace std;

int type[19][3][2] = {{{0, 1}, {0, 2}, {0, 3}},
                    {{1, 0}, {2, 0}, {3, 0}},
                    {{0, 1}, {1, 0}, {1, 1}},
                    {{0, 1}, {0, 2}, {1, 2}},
                    {{0, 1}, {0, 2}, {-1, 2}},
                    {{0, 1}, {0, 2}, {1, 0}},
                    {{0, 1}, {0, 2}, {-1, 0}},
                    {{1, 0}, {2, 0}, {2, 1}},
                    {{1, 0}, {2, 0}, {2, -1}},
                    {{1, 0}, {2, 0}, {0, 1}},
                    {{1, 0}, {2, 0}, {0, -1}},
                    {{1, 0}, {1, 1}, {2, 1}},
                    {{1, 0}, {1, -1}, {2, -1}},
                    {{0, 1}, {1, 1}, {1, 2}},
                    {{0, 1}, {-1, 1}, {-1, 2}},
                    {{1, 0}, {1, 1}, {2, 0}},
                    {{1, 0}, {1, -1}, {2, 0}},
                    {{0, 1}, {1, 1}, {0, 2}},
                    {{0, 1}, {-1, 1}, {0, 2}}};

int main(void)
{
    int n, m, ans = 0, cand, flag, xx, yy;
    int arr[501][501] = {0, };

    scanf("%d%d", &n, &m);

    for(int i  = 0; i < n; ++i)
        for(int j = 0; j < m; ++j)
            scanf("%d", &arr[i][j]);

    for(int i = 0; i < n; ++i){
        for(int j = 0; j < m; ++j){
            for(int k = 0; k < 19; ++k){
                flag = 0;
                for(int l = 0; l < 3; ++l){
                    xx = j+type[k][l][0];
                    yy = i+type[k][l][1];
                    if(xx >= m || xx < 0 || yy >= n || yy < 0){
                        flag++;
                        break;
                    }
                }
                if(flag)
                    continue;
                else{
                    cand = arr[i][j] + arr[i+type[k][0][1]][j+type[k][0][0]] + arr[i+type[k][1][1]][j+type[k][1][0]] + arr[i+type[k][2][1]][j+type[k][2][0]];
                    ans = max(ans, cand);
                }
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

 

주의점 )

- 모양 중복

- 종류 수(19가지)

- 인덱스 범위

반응형
반응형

책 링크

출처 - 교보문고

이 카테고리에는 부족한 영어실력으로 원서로 자료구조를 공부하면서 정리한 내용을 올릴 예정이다.

추가로 기억하고 싶은 내용이나 책에 나오는 모르는 영단어도 정리 예정이다.

반응형

'독서 > C 자료구조 원서' 카테고리의 다른 글

3장: 스택과 큐  (0) 2020.09.04
2장: 배열과 구조체  (0) 2020.08.07
1장: 기본 개념  (0) 2020.03.17
반응형

문제 링크

 

1476번: 날짜 계산

준규가 사는 나라는 우리가 사용하는 연도와 다른 방식을 이용한다. 준규가 사는 나라에서는 수 3개를 이용해서 연도를 나타낸다. 각각의 수는 지구, 태양, 그리고 달을 나타낸다. 지구를 나타내는 수를 E, 태양을 나타내는 수를 S, 달을 나타내는 수를 M이라고 했을 때, 이 세 수는 서로 다른 범위를 가진다. (1 ≤ E ≤ 15, 1 ≤ S ≤ 28, 1 ≤ M ≤ 19) 우리가 알고있는 1년은 준규가 살고있는 나라에서는 1 1 1로 나타낼 수 있다. 1

www.acmicpc.net

 

풀이 ) 완전 탐색

 

  서로 다른 세 수에 대해서 나머지라고 생각해서 풀면 되는 문제이다. 공배수 개념

 

#include <cstdio>
using namespace std;

int main(void)
{
    int e, s, m, ans;
    scanf("%d%d%d", &e, &s, &m);

    ans = e-1;
    while(1){
        if(ans % 28 == s-1 && ans % 19 == m-1)
            break;
        else
            ans += 15;
    }
    printf("%d\n", ans+1);
    return 0;
}

 

주의점 )

 

- 예제 입력 4는 반드시 해보기 바란다.

 

주어지는 e, s, m의 값이 0부터가 아닌 1부터 시작하기 때문에 나머지라고 생각하여 바로 모듈러 연산을 하면 안되고 답 후보에서 1을 뺀 후 출력하기 전에 1을 더해주면 된다.

반응형
반응형

C문제 링크

 

2309번: 일곱 난쟁이

아홉 개의 줄에 걸쳐 난쟁이들의 키가 주어진다. 주어지는 키는 100을 넘지 않는 자연수이며, 아홉 난쟁이의 키는 모두 다르며, 가능한 정답이 여러 가지인 경우에는 아무거나 출력한다.

www.acmicpc.net

 

풀이 ) 완전 탐색

 

  일곱 난쟁이의 키의 합이 100이므로 전체 9명의 합을 tot라고 했을 때

완전탐색을 통해서 2명의 합이 tot-100인 조합을 찾는 문제이다.

 

정렬은 sort()를 사용했다.

 

#include <cstdio>	// scanf(), printf()
#include <algorithm>	// sort()
using namespace std;

int main(void)
{
    int arr[10] = {0, }, tot = 0;

    for(int i = 0; i < 9; ++i){
        scanf("%d", arr+i);
        tot += arr[i];
    }
    sort(arr, arr+9);

    int flag = 0;
    for(int i = 0; i < 8; ++i){
        for(int j = i; j < 9; ++j){
            if (arr[i]+arr[j] == tot-100){
                arr[i] = 0;
                arr[j] = 0;
                flag++;
                break;
            }
        }
        if(flag)
            break;
    }
    for(int i= 0; i < 9; ++i)
        if(arr[i])
            printf("%d\n", arr[i]);
}

 

반응형
반응형

문제 링크

 

algospot.com :: FESTIVAL

록 페스티벌 문제 정보 문제 커다란 공연장을 빌려서 록 페스티벌을 개최하려고 합니다. 이 페스티벌은 여러 날 동안 진행되며, 하루에 한 팀의 밴드가 공연장에서 콘서트를 하게 됩니다. 전체 밴드를 몇 팀 섭외할 지는 아직 결정하지 않았지만, 페스티벌의 간판 스타인 L개의 팀은 이미 섭외가 끝난 상태입니다. 따라서 페스티벌은 최소 L일 이상 진행하게 됩니다. 이번에 사용할 공연장은 하루 빌리는 데 드는 비용이 매일 매일 다릅니다. 때문에 공연 일정을 잘 정해

algospot.com

 

처음에 생각한 풀이 )

 

  첫 팀부터 시작하여 L팀을 선택하여 평균을 구한 후 다음 팀을 확인하여 이미 구한 평균보다 큰 팀이 나오면 다음 루프를 돌리면 된다고 생각했다.

 

반례 )

 

5 3

1 4 3 4 1

 

  생각한대로 구현을 하면  (1+4+3) / 3 < 4 이기 때문에 최솟값으로 8/3을 저장한 후 다음 루프를 돌지만

답인 탐색하지 않게 되는 (1+4+3+4+1) / 5이다.

 

#include <cstdio>	// scanf(), printf()
#include <algorithm>	// min()
using namespace std;
 
int main(void)
{
    int c, n, l;
    int i, j;
    double ans;
 
    scanf("%d", &c);
    while(c--){
        // a[]는 입력으로 받는 각 팀의 비용, b[]는 최솟값을 확인하기 위한 팀 비용의 합
        int teamNum, a[1000], b[1000];
	ans = 1e9;
 
        scanf("%d%d", &n, &l);
        for(int i = 0; i < n; i++)
            scanf("%d", a+i);

        for(i = 0; i <= n-l; i++){
            teamNum = l;
	        b[i] = 0;
            // 최소 팀의 합
            for(j = i; j < i+l; j++)
                b[i] += a[j];
            for(; j < n; j++){
                // 평균 이하의 팀만 추가
                // 나누기 연산 시 오차 발생 때문에 곱셈 연산 사용
                if((double)a[j]*teamNum <= (double)b[i]){
                    b[i] += a[j];
                    teamNum++;
                }
                else
                    break;
            }
            ans = min(ans, (double)b[i]/teamNum);
        }
        printf("%.11f\n", ans);
    }
    return 0;
}

 

 

풀이 )

 

  위에 반례를 통해 모두 탐색해야 된다는 것을 알게 되었으므로 완전탐색을 통해 구했다.

  

#include <cstdio>
#include <algorithm>
using namespace std;

int main(void)
{
    int c, n, l;
    int i, j, k, sum, check;
    int teamNum, a[1000];
    double ans;

    scanf("%d", &c);
    while(c--){
        ans = 1e9;
        scanf("%d%d", &n, &l);
        for(i = 0; i < n; ++i){
            scanf("%d", a+i);
        }
        for(i = 0; i <= n-l; ++i){
            for(j = l; j <= n-i; ++j){
                sum = 0;
                for(k = 0; k < j; ++k){
                    sum += a[i+k];
                }
                ans = min(ans, (double)sum / j);
            }
        }
        printf("%.11f\n", ans);
    }
    return 0;
}

 

주의점 )

 

- 자료형 (float -> double)

- 출력 자리 수 (7자리 이상)

반응형

'문제풀이 > 알고스팟' 카테고리의 다른 글

[C++] 알고스팟 - CLOCKSYNC  (0) 2020.12.28
[C++] 알고스팟 - BOARDCOVER  (0) 2020.12.28
[C++] 알고스팟 - PICNIC  (0) 2020.11.01

+ Recent posts