728x90
반응형
  • 문제

'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다.

게임은 NxN 정사각 보드위에서 진행되고, 몇몇 칸에는 사과가 놓여져 있다. 보드의 상하좌우 끝에 벽이 있다. 게임이 시작할때 뱀은 맨위 맨좌측에 위치하고 뱀의 길이는 1 이다. 뱀은 처음에 오른쪽을 향한다.

뱀은 매 초마다 이동을 하는데 다음과 같은 규칙을 따른다.

  • 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.
  • 만약 벽이나 자기자신의 몸과 부딪히면 게임이 끝난다.
  • 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
  • 만약 이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸길이는 변하지 않는다.

사과의 위치와 뱀의 이동경로가 주어질 때 이 게임이 몇 초에 끝나는지 계산하라.

  • 입력

첫째 줄에 보드의 크기 N이 주어진다. (2 ≤ N ≤ 100) 다음 줄에 사과의 개수 K가 주어진다. (0 ≤ K ≤ 100)

다음 K개의 줄에는 사과의 위치가 주어지는데, 첫 번째 정수는 행, 두 번째 정수는 열 위치를 의미한다. 사과의 위치는 모두 다르며, 맨 위 맨 좌측 (1행 1열) 에는 사과가 없다.

다음 줄에는 뱀의 방향 변환 횟수 L 이 주어진다. (1 ≤ L ≤ 100)

다음 L개의 줄에는 뱀의 방향 변환 정보가 주어지는데, 정수 X와 문자 C로 이루어져 있으며. 게임 시작 시간으로부터 X초가 끝난 뒤에 왼쪽(C가 'L') 또는 오른쪽(C가 'D')로 90도 방향을 회전시킨다는 뜻이다. X는 10,000 이하의 양의 정수이며, 방향 전환 정보는 X가 증가하는 순으로 주어진다.

  • 출력

첫째 줄에 게임이 몇 초에 끝나는지 출력한다.

  • 예제 입력
6
3
3 4
2 5
5 3
3
3 D
15 L
17 D
10
4
1 2
1 3
1 4
1 5
4
8 D
10 D
11 D
13 L
10
5
1 5
1 3
1 2
1 6
1 7
4
8 D
10 D
11 D
13 L
  • 예제 출력
9
21
13
  • 접근방식

1. 뱀이 사과를 먹으면 앞부분 추가, 사과를 안먹고 움직이면 끝 부분을 삭제하고 앞부분을 추가하는 식으로 이동 > deque사용
2. 벽 또는 자기 몸에 충돌하면 끝 > 방문처리 visited가 필요
3. 방향 전환 dy, dx를 사용, 모듈러 연산을 통해 방향 전환 가능 (4방향)

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <deque>
#include <tuple>

using namespace std;

const int dy[] = { -1,0,1,0 };
const int dx[] = { 0,1,0 ,-1 };
int n, k, l, x, y_, x_, idx, direction = 1, _map[104][104], visited[104][104], result;
char c;
vector<pair<int, int>> time_vector;
deque<pair<int, int>> dq;

int main()
{
    cin >> n >> k;

    for (int i = 0; i < k; i++)
    {
        cin >> y_ >> x_;
        _map[--y_][--x_] = 1;

    }
    cin >> l;

    for (int i = 0; i < l; i++)
    {
        cin >> x >> c;
        if (c == 'D')
        {
            time_vector.push_back({ x,1 }); // 시간 정보와 방향 정보 저장 (D == 1, C == 3)
        }
        else
        {
            time_vector.push_back({ x,3 });
        }
    }

    dq.push_back({ 0,0 });

    while (dq.size())
    {
        result++;
        tie(y_, x_) = dq.front();
        int ny = y_ + dy[direction];
        int nx = x_ + dx[direction];
        if (ny >= n || ny < 0 || nx >= n || nx < 0 || visited[ny][nx])  break; // 사망처리

        if (!_map[ny][nx]) // 사과가 없으면
        {
            visited[dq.back().first][dq.back().second] = 0; // 꼬리 부분 지우고
            dq.pop_back();
        }
        else
        {
            _map[ny][nx] = 0; // 사과 먹은 처리
        }

        visited[ny][nx] = 1;
        dq.push_front({ ny,nx }); // 머리 부분 채워주기
        if (result == time_vector[idx].first)
        {
            direction = (direction + time_vector[idx].second) % 4; // 방향 전환
            idx++;
        }
    }

    cout << result;

    return 0;
}
 

3190번: 뱀

'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다. 게임

www.acmicpc.net

 

728x90
반응형
728x90
반응형
  • 문제

2048 게임은 4×4 크기의 보드에서 혼자 즐기는 재미있는 게임이다. 이 링크를 누르면 게임을 해볼 수 있다.

이 게임에서 한 번의 이동은 보드 위에 있는 전체 블록을 상하좌우 네 방향 중 하나로 이동시키는 것이다. 이때, 같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다. 한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다. (실제 게임에서는 이동을 한 번 할 때마다 블록이 추가되지만, 이 문제에서 블록이 추가되는 경우는 없다)

<그림 1>의 경우에서 위로 블록을 이동시키면 <그림 2>의 상태가 된다. 여기서, 왼쪽으로 블록을 이동시키면 <그림 3>의 상태가 된다.

<그림 4>의 상태에서 블록을 오른쪽으로 이동시키면 <그림 5>가 되고, 여기서 다시 위로 블록을 이동시키면 <그림 6>이 된다. 여기서 오른쪽으로 블록을 이동시켜 <그림 7>을 만들 수 있다.

<그림 8>의 상태에서 왼쪽으로 블록을 옮기면 어떻게 될까? 2가 충돌하기 때문에, 4로 합쳐지게 되고 <그림 9>의 상태가 된다.

<그림 10>에서 위로 블록을 이동시키면 <그림 11>의 상태가 된다. 

<그림 12>의 경우에 위로 블록을 이동시키면 <그림 13>의 상태가 되는데, 그 이유는 한 번의 이동에서 이미 합쳐진 블록은 또 합쳐질 수 없기 때문이다.

마지막으로, 똑같은 수가 세 개가 있는 경우에는 이동하려고 하는 쪽의 칸이 먼저 합쳐진다. 예를 들어, 위로 이동시키는 경우에는 위쪽에 있는 블록이 먼저 합쳐지게 된다. <그림 14>의 경우에 위로 이동하면 <그림 15>를 만든다.

이 문제에서 다루는 2048 게임은 보드의 크기가 N×N 이다. 보드의 크기와 보드판의 블록 상태가 주어졌을 때, 최대 5번 이동해서 만들 수 있는 가장 큰 블록의 값을 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2보다 크거나 같고, 1024보다 작거나 같은 2의 제곱꼴이다. 블록은 적어도 하나 주어진다.

  • 출력

최대 5번 이동시켜서 얻을 수 있는 가장 큰 블록을 출력한다.

  • 예제 입력
3
2 2 2
4 4 4
8 8 8
  • 예제 출력
16
  • 접근방식

이동해서 합치는 함수를 만들고 그것을 90도로 돌리는 함수를 만들면 계속 사용할 수 있다.
슬라이드 하고 90도로 돌리는걸 4번 반복하면 4방향을 모두 슬라이드 하는 것이니 이 중 가장 큰 값을 구하면 된다.
중간에 돌리거나 이동하거나 할 때 temp를 사용해서 보드 갱신

  • 코드
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

int n, result;

struct Board
{
    int board[24][24];

    void rotate90()
    {
        int temp[24][24];
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                temp[i][j] = board[n - j - 1][i];
            }
        }
        memcpy(board, temp, sizeof(board));
    }

    void move()
    {
        int temp[24][24];
        for (int i = 0; i < n; i++)
        {
            int c = -1, d = 0;
            for (int j = 0; j < n; j++)
            {
                if (board[i][j] == 0)    continue;
                if (d && board[i][j] == temp[i][c])
                {
                    temp[i][c] *= 2;
                    d = 0;
                }
                else
                {
                    temp[i][++c] = board[i][j];
                    d = 1;
                }
            }
            for (c++; c < n; c++)
            {
                temp[i][c] = 0;
            }
        }
        memcpy(board, temp, sizeof(board));
    }

    void get_max()
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                result = max(result, board[i][j]);
            }
        }
    }
};

void solution(Board c, int here)
{
    if (here == 5)
    {
        c.get_max();
        return;
    }

    for (int i = 0; i < 4; i++) // 4방향 모두 슬라이드
    {
        Board d = c;
        d.move();
        solution(d, here + 1);
        c.rotate90();
    }
    return;
}

int main()
{
    cin >> n;

    Board c;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cin >> c.board[i][j];
        }
    }

    solution(c, 0);
    cout << result;

    return 0;
}
 

12100번: 2048 (Easy)

첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 17406번 배열 돌리기 4  (0) 2024.03.25
[C++]/백준 3190번 뱀  (1) 2024.03.25
[C++]/백준 17144번 미세먼지 안녕!  (0) 2024.03.20
[C++]/백준 1700번 멀티탭 스케줄링  (1) 2024.03.20
[C++]/백준 3273번 두 수의 합  (0) 2024.03.20
728x90
반응형
  • 문제

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사과는 뛰어난 코딩 실력을 이용해 각 칸 (r, c)에 있는 미세먼지의 양을 실시간으로 모니터링하는 시스템을 개발했다. (r, c)는 r행 c열을 의미한다.

공기청정기는 항상 1번 열에 설치되어 있고, 크기는 두 행을 차지한다. 공기청정기가 설치되어 있지 않은 칸에는 미세먼지가 있고, (r, c)에 있는 미세먼지의 양은 Ar,c이다.

1초 동안 아래 적힌 일이 순서대로 일어난다.

  1. 미세먼지가 확산된다. 확산은 미세먼지가 있는 모든 칸에서 동시에 일어난다.
    • (r, c)에 있는 미세먼지는 인접한 네 방향으로 확산된다.
    • 인접한 방향에 공기청정기가 있거나, 칸이 없으면 그 방향으로는 확산이 일어나지 않는다.
    • 확산되는 양은 Ar,c/5이고 소수점은 버린다. 즉, ⌊Ar,c/5⌋이다.
    • (r, c)에 남은 미세먼지의 양은 Ar,c - ⌊Ar,c/5⌋×(확산된 방향의 개수) 이다.
  2. 공기청정기가 작동한다.
    • 공기청정기에서는 바람이 나온다.
    • 위쪽 공기청정기의 바람은 반시계방향으로 순환하고, 아래쪽 공기청정기의 바람은 시계방향으로 순환한다.
    • 바람이 불면 미세먼지가 바람의 방향대로 모두 한 칸씩 이동한다.
    • 공기청정기에서 부는 바람은 미세먼지가 없는 바람이고, 공기청정기로 들어간 미세먼지는 모두 정화된다.

다음은 확산의 예시이다.

왼쪽과 위쪽에 칸이 없기 때문에, 두 방향으로만 확산이 일어났다.

인접한 네 방향으로 모두 확산이 일어난다.

공기청정기가 있는 칸으로는 확산이 일어나지 않는다.

공기청정기의 바람은 다음과 같은 방향으로 순환한다.

방의 정보가 주어졌을 때, T초가 지난 후 구사과의 방에 남아있는 미세먼지의 양을 구해보자.

  • 입력

첫째 줄에 R, C, T (6 ≤ R, C ≤ 50, 1 ≤ T ≤ 1,000) 가 주어진다.

둘째 줄부터 R개의 줄에 Ar,c (-1 ≤ Ar,c ≤ 1,000)가 주어진다. 공기청정기가 설치된 곳은 Ar,c가 -1이고, 나머지 값은 미세먼지의 양이다. -1은 2번 위아래로 붙어져 있고, 가장 윗 행, 아랫 행과 두 칸이상 떨어져 있다.

  • 출력

첫째 줄에 T초가 지난 후 구사과 방에 남아있는 미세먼지의 양을 출력한다.

  • 예제 입력
7 8 1
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
7 8 2
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
7 8 3
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
7 8 4
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
7 8 5
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
7 8 20
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
7 8 30
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
7 8 50
0 0 0 0 0 0 0 9
0 0 0 0 3 0 0 8
-1 0 5 0 0 0 22 0
-1 8 0 0 0 0 0 0
0 0 0 0 0 10 43 0
0 0 5 0 15 0 0 0
0 0 40 0 0 0 20 0
  • 예제 출력
188
188
186
178
172
71
52
46
  • 접근방식

우선 미세먼지 확산을 구현하고 공기 청정기가 갈 방향과 밀어내는 것을 구현하면 된다.

미세먼지를 동시에 확산해야하며 temp에 저장해둬서 동시에 확산해야함 (아니면 순차적 확산으로 값 오류남)
공기 청정기는 벽을 만나면 방향을 바꾸는거로 설정, y방향이 다른 두 개의 dy가 필요

1. 값을 입력 받고 공기 청정기 방향부터 확인 (위로갈 v1, 아래로갈 v2 저장)
2. while(t--)로 미세 먼지 확산후 밀어내기
3. 종료되면 미세 먼지 총 합 더하고 출력

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <tuple>

using namespace std;

int r, c, t, result, a[54][54], temp[54][54];
vector<pair<int, int>> v1, v2;

int dy1[] = { 0, -1, 0, 1 };
int dx1[] = { 1, 0, -1, 0 };
int dy2[] = { 0, 1, 0, -1 };
int dx2[] = { 1, 0, -1, 0 };

void mise_munge(int dy[], int dx[])
{
    fill(&temp[0][0], &temp[0][0] + 54 * 54, 0);
    queue<pair<int, int>> q;
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            if (a[i][j] != -1 && a[i][j])
            {
                q.push({ i, j });
            }
        }
    }
    while (q.size())
    {
        int y, x;
        tie(y, x) = q.front();
        q.pop();
        int spread = a[y][x] / 5;
        for (int i = 0; i < 4; i++)
        {
            int ny = y + dy[i];
            int nx = x + dx[i];
            if (ny < 0 || ny >= r || nx < 0 || nx >= c || a[ny][nx] == -1) continue;
            temp[ny][nx] += spread;
            a[y][x] -= spread;
        }
    }
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            a[i][j] += temp[i][j];
        }
    }
    return;
}

vector<pair<int, int>> chung(int sy, int sx, int dy[], int dx[])
{
    vector<pair<int, int>> v;
    int cnt = 0;
    int y = sy;
    int x = sx;
    while (true)
    {
        int ny = y + dy[cnt];
        int nx = x + dx[cnt];
        if (ny == sy && nx == sx)   break;
        if (ny < 0 || ny >= r || nx < 0 || nx >= c) {
            cnt++;
            ny = y + dy[cnt];
            nx = x + dx[cnt];
        }
        if (ny == sy && nx == sx)   break;
        y = ny;
        x = nx;
        v.push_back({ ny, nx });
    }
    return v;
}

void push_air(vector<pair<int, int>>& v)
{
    for (int i = v.size() - 1; i > 0; i--)
    {
        a[v[i].first][v[i].second] = a[v[i - 1].first][v[i - 1].second];
    }
    a[v[0].first][v[0].second] = 0;
    return;
}

int main()
{
    cin >> r >> c >> t;
    bool flag = 1;
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            cin >> a[i][j];
            if (a[i][j] == -1)
            {
                if (flag)
                {
                    v1 = chung(i, j, dy1, dx1);
                    flag = false;
                }
                else 
                {
                    v2 = chung(i, j, dy2, dx2);
                }
            }
        }
    }
    while (t--)
    {
        mise_munge(dy1, dx1);
        push_air(v1);
        push_air(v2);
    }
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            if (a[i][j] != -1)
            {
                result += a[i][j];
            }
        }
    }
    cout << result;
}
 

17144번: 미세먼지 안녕!

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사

www.acmicpc.net

 

728x90
반응형

'C++ > BOJ' 카테고리의 다른 글

[C++]/백준 3190번 뱀  (1) 2024.03.25
[C++]/백준 12100번 2048(Easy)  (0) 2024.03.21
[C++]/백준 1700번 멀티탭 스케줄링  (1) 2024.03.20
[C++]/백준 3273번 두 수의 합  (0) 2024.03.20
[C++]/백준 13144번 List of Unique Numbers  (0) 2024.03.19
728x90
반응형
  • 문제

기숙사에서 살고 있는 준규는 한 개의 멀티탭을 이용하고 있다. 준규는 키보드, 헤어드라이기, 핸드폰 충전기, 디지털 카메라 충전기 등 여러 개의 전기용품을 사용하면서 어쩔 수 없이 각종 전기용품의 플러그를 뺐다 꽂았다 하는 불편함을 겪고 있다. 그래서 준규는 자신의 생활 패턴을 분석하여, 자기가 사용하고 있는 전기용품의 사용순서를 알아내었고, 이를 기반으로 플러그를 빼는 횟수를 최소화하는 방법을 고안하여 보다 쾌적한 생활환경을 만들려고 한다.

예를 들어 3 구(구멍이 세 개 달린) 멀티탭을 쓸 때, 전기용품의 사용 순서가 아래와 같이 주어진다면,

  1. 키보드
  2. 헤어드라이기
  3. 핸드폰 충전기
  4. 디지털 카메라 충전기
  5. 키보드
  6. 헤어드라이기

키보드, 헤어드라이기, 핸드폰 충전기의 플러그를 순서대로 멀티탭에 꽂은 다음 디지털 카메라 충전기 플러그를 꽂기 전에 핸드폰충전기 플러그를 빼는 것이 최적일 것이므로 플러그는 한 번만 빼면 된다.

  • 입력

첫 줄에는 멀티탭 구멍의 개수 N (1 ≤ N ≤ 100)과 전기 용품의 총 사용횟수 K (1 ≤ K ≤ 100)가 정수로 주어진다. 두 번째 줄에는 전기용품의 이름이 K 이하의 자연수로 사용 순서대로 주어진다. 각 줄의 모든 정수 사이는 공백문자로 구분되어 있다.

  • 출력

하나씩 플러그를 빼는 최소의 횟수를 출력하시오.

  • 예제 입력
2 7
2 3 2 3 1 2 7
  • 예제 출력
2
  • 접근방식

일단 미래의 나타날 숫자를 미리 알고 있으므로 가장 먼 미래(뒤에 있는 인덱스)에 나타나는 수를 찾아서 바꾸고 경우의 수를 1 추가하면 된다.
방문 처리할 visited가 필요하고 전기 용품이 꽂혀있는 벡터가 필요하다.

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int n, k, result, a[104], visited[104];
vector<int> v;

int main()
{
    cin >> n >> k;

    for (int i = 0; i < k; i++)
    {
        cin >> a[i];
    }

    for (int i = 0; i < k; i++)
    {
        if (!visited[a[i]])
        {
            if (v.size() == n)
            {
                int last_idx = 0, pos;
                for (int element : v)
                {
                    int here_pick = 99999999;
                    for (int j = i + 1; j < k; j++) // 가장 먼 미래에 참조 되는 것을 찾음
                    {
                        if (element == a[j])
                        {
                            here_pick = j;
                            break;
                        }
                    }
                    if (last_idx < here_pick)
                    {
                        last_idx = here_pick;
                        pos = element;
                    }
                }
                visited[pos] = 0;
                result++;
                v.erase(find(v.begin(), v.end(), pos));
            }
            v.push_back(a[i]);
            visited[a[i]] = 1;
        }
    }

    cout << result;
    return 0;
}
 

1700번: 멀티탭 스케줄링

기숙사에서 살고 있는 준규는 한 개의 멀티탭을 이용하고 있다. 준규는 키보드, 헤어드라이기, 핸드폰 충전기, 디지털 카메라 충전기 등 여러 개의 전기용품을 사용하면서 어쩔 수 없이 각종 전

www.acmicpc.net

 

728x90
반응형
728x90
반응형
  • 문제

n개의 서로 다른 양의 정수 a1, a2, ..., an으로 이루어진 수열이 있다. ai의 값은 1보다 크거나 같고, 1000000보다 작거나 같은 자연수이다. 자연수 x가 주어졌을 때, ai + aj = x (1 ≤ i < j ≤ n)을 만족하는 (ai, aj)쌍의 수를 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 수열의 크기 n이 주어진다. 다음 줄에는 수열에 포함되는 수가 주어진다. 셋째 줄에는 x가 주어진다. (1 ≤ n ≤ 100000, 1 ≤ x ≤ 2000000)

  • 출력

문제의 조건을 만족하는 쌍의 개수를 출력한다.

  • 예제 입력
9
5 12 7 10 9 1 2 3 11
13
  • 예제 출력
3
  • 접근방식

두 수를 가지고 무엇을 한다고 했을 때 투 포인터로 생각을 했고 정렬을 하고 left와 right를 정해주고 right의 값이 left보다 크면 탐색을 종료하는 반복문을 만들어 두 수의 합이 x와 같으면 경우의 수가 증가하고 right를 감소시키고 두 수의 합이 x보다 크면 right만 감소하여 다시 탐색, 두 수의 합이 x보다 작으면 left만 증가시켜 다시 탐색한다.

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int n, m, x, result;
vector<int> v;

int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> m;
        v.push_back(m);
    }

    sort(v.begin(), v.end());

    int left_p = 0, right_p = n - 1;
    while (left_p < right_p)
    {
        if (v[left_p] + v[right_p] == x)
        {
            right_p--;
            result++;
        }
        else if (v[left_p] + v[right_p] > x)
        {
            right_p--;
        }
        else if (v[left_p] + v[right_p] < x)
        {
            left_p++;
        }
    }
    cout << result;
    return 0;
}
 

3273번: 두 수의 합

n개의 서로 다른 양의 정수 a1, a2, ..., an으로 이루어진 수열이 있다. ai의 값은 1보다 크거나 같고, 1000000보다 작거나 같은 자연수이다. 자연수 x가 주어졌을 때, ai + aj = x (1 ≤ i < j ≤ n)을 만족하는

www.acmicpc.net

 

728x90
반응형
728x90
반응형
  • 문제

길이가 N인 수열이 주어질 때, 수열에서 연속한 1개 이상의 수를 뽑았을 때 같은 수가 여러 번 등장하지 않는 경우의 수를 구하는 프로그램을 작성하여라.

  • 입력

첫 번째 줄에는 수열의 길이 N이 주어진다. (1 ≤ N ≤ 100,000)

두 번째 줄에는 수열을 나타내는 N개의 정수가 주어진다. 수열에 나타나는 수는 모두 1 이상 100,000 이하이다.

  • 출력

조건을 만족하는 경우의 수를 출력한다.

  • 예제 입력
5
1 2 3 4 5
5
1 2 3 1 2
5
1 1 1 1 1
  • 예제 출력
15
12
5
  • 접근방식

중복되는 수를 체크하는 배열이 필요할 것으로 보이고 시작지점 startNumebr부터 시작해서 중복되는 수가 나오면 endNumber로 저장해두고 startNumber를 증가시키면서 경우의 수를 구하는 것으로 접근했다.
등차 수열의 합의 공식을 사용해서 n(n+1)/2를 더하면 된다.

  • 코드
#include <iostream>
#include <algorithm>

using namespace std;

long long n, startNumber, endNumber, check[100004], a[100004], result;

int main()
{
    cin >> n;

    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }

    while (endNumber < n)
    {
        if (!check[a[endNumber]])
        {
            check[a[endNumber]]++;
            endNumber++;
        }
        else
        {
            result += (endNumber - startNumber);
            check[a[startNumber]]--;
            startNumber++;
        }
    }
    
    result += (long long)(endNumber - startNumber) * (endNumber - startNumber + 1) / 2;
    cout << result;

    return 0;
}
 

13144번: List of Unique Numbers

길이가 N인 수열이 주어질 때, 수열에서 연속한 1개 이상의 수를 뽑았을 때 같은 수가 여러 번 등장하지 않는 경우의 수를 구하는 프로그램을 작성하여라.

www.acmicpc.net

 

728x90
반응형
728x90
반응형
  • 문제

하나 이상의 연속된 소수의 합으로 나타낼 수 있는 자연수들이 있다. 몇 가지 자연수의 예를 들어 보면 다음과 같다.

  • 3 : 3 (한 가지)
  • 41 : 2+3+5+7+11+13 = 11+13+17 = 41 (세 가지)
  • 53 : 5+7+11+13+17 = 53 (두 가지)

하지만 연속된 소수의 합으로 나타낼 수 없는 자연수들도 있는데, 20이 그 예이다. 7+13을 계산하면 20이 되기는 하나 7과 13이 연속이 아니기에 적합한 표현이 아니다. 또한 한 소수는 반드시 한 번만 덧셈에 사용될 수 있기 때문에, 3+5+5+7과 같은 표현도 적합하지 않다.

자연수가 주어졌을 때, 이 자연수를 연속된 소수의 합으로 나타낼 수 있는 경우의 수를 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 4,000,000)

  • 출력

첫째 줄에 자연수 N을 연속된 소수의 합으로 나타낼 수 있는 경우의 수를 출력한다.

  • 예제 입력
20
3
41
53
  • 예제 출력
0
1
3
2
  • 접근방식

소수를 먼저 구해야해서 에라스토테네스의 체를 사용했고, 구간을 정해야 하는데 low와 high을 사용한 투포인터로 구간을 정해서 구간들의 갯수가 해당 소수를 만들 수 있는 경우의 수이기 때문에 더하면 된다.

  • 코드
#include <iostream>
#include <algorithm>

using namespace std;

bool check[4000001];
int n, a[2000001], p, low, high, result, sum;

int main()
{
    cin >> n;
    for (int i = 2; i <= n; i++)
    {
        if (check[i])    continue;
        for (int j = i * 2; j <= n; j += i)
        {
            check[j] = 1;
        }
    }

    for (int i = 2; i <= n; i++)
    {
        if (!check[i]) // 소수라면 집어넣기
        {
            a[p++] = i;
        }
    }

    while (1)
    {
        if (sum >= n) // low를 증가 시키는 조건
        {
            sum -= a[low++];
        }
        else if (high == p)  break;
        else // high을 증가 시키는 조건
        {
            sum += a[high++];
        }
        if (sum == n)
        {
            result++;
        }
    }

    cout << result;

    return 0;
}
 

1644번: 소수의 연속합

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 4,000,000)

www.acmicpc.net

 

728x90
반응형
728x90
반응형
  • 문제

세계적인 도둑 상덕이는 보석점을 털기로 결심했다.

상덕이가 털 보석점에는 보석이 총 N개 있다. 각 보석은 무게 Mi와 가격 Vi를 가지고 있다. 상덕이는 가방을 K개 가지고 있고, 각 가방에 담을 수 있는 최대 무게는 Ci이다. 가방에는 최대 한 개의 보석만 넣을 수 있다.

상덕이가 훔칠 수 있는 보석의 최대 가격을 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 N과 K가 주어진다. (1 ≤ N, K ≤ 300,000)

다음 N개 줄에는 각 보석의 정보 Mi와 Vi가 주어진다. (0 ≤ Mi, Vi ≤ 1,000,000)

다음 K개 줄에는 가방에 담을 수 있는 최대 무게 Ci가 주어진다. (1 ≤ Ci ≤ 100,000,000)

모든 숫자는 양의 정수이다.

  • 출력

첫째 줄에 상덕이가 훔칠 수 있는 보석 가격의 합의 최댓값을 출력한다.

  • 예제 입력
2 1
5 10
100 100
11
3 2
1 65
5 23
2 99
10
2
  • 예제 출력
10
164
  • 접근방식

우선, M과 V를 저장하는 벡터를 준비하고 가방의 최대 갯수를 저장하는 벡터를 준비한다.
두개의 벡터를 오름차순으로 정렬하고 가방에 들어갈 수 있는 보석을 찾고 PQ(우선순위 큐)에 넣어준다.
우선순위 큐는 내림차순으로 설정해주면 젤 위에 있는 값이 가장 가격이 높은 보석이기때문에 top만 결과에 넣어주고 pop하면 된다.
여기서 범위가 Ci의 경우 100,000,000까지 이기 때문에 long long 자료형을 사용해야한다.

  • 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

long long n, m, v, k, c, result;
vector<pair<int, int>> v1;
vector<int> v2;

int main()
{
    cin >> n >> k;

    for (int i = 0; i < n; i++)
    {
        cin >> m >> v;
        v1.push_back({ m,v });
    }

    for (int i = 0; i < k; i++)
    {
        cin >> c;
        v2.push_back(c);
    }

    sort(v1.begin(), v1.end());
    sort(v2.begin(), v2.end());
    priority_queue<int> pq;
    int j = 0;
    for (int i = 0; i < k; i++) 
    {
        while (j < n && v1[j].first <= v2[i])
        {
            pq.push(v1[j++].second);
        }
        if (pq.size())
        {
            result += pq.top();
            pq.pop();
        }
    }
    cout << result;
    return 0;
}
 

1202번: 보석 도둑

첫째 줄에 N과 K가 주어진다. (1 ≤ N, K ≤ 300,000) 다음 N개 줄에는 각 보석의 정보 Mi와 Vi가 주어진다. (0 ≤ Mi, Vi ≤ 1,000,000) 다음 K개 줄에는 가방에 담을 수 있는 최대 무게 Ci가 주어진다. (1 ≤ Ci

www.acmicpc.net

 

728x90
반응형

+ Recent posts