728x90
반응형
  • 문제

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다.

1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할 수 있다.

CCTV는 감시할 수 있는 방향에 있는 칸 전체를 감시할 수 있다. 사무실에는 벽이 있는데, CCTV는 벽을 통과할 수 없다. CCTV가 감시할 수 없는 영역은 사각지대라고 한다.

CCTV는 회전시킬 수 있는데, 회전은 항상 90도 방향으로 해야 하며, 감시하려고 하는 방향이 가로 또는 세로 방향이어야 한다.

0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0

지도에서 0은 빈 칸, 6은 벽, 1~5는 CCTV의 번호이다. 위의 예시에서 1번의 방향에 따라 감시할 수 있는 영역을 '#'로 나타내면 아래와 같다.

CCTV는 벽을 통과할 수 없기 때문에, 1번이 → 방향을 감시하고 있을 때는 6의 오른쪽에 있는 칸을 감시할 수 없다.

0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5

위의 예시에서 감시할 수 있는 방향을 알아보면 아래와 같다.

CCTV는 CCTV를 통과할 수 있다. 아래 예시를 보자.

0 0 2 0 3
0 6 0 0 0
0 0 6 6 0
0 0 0 0 0

위와 같은 경우에 2의 방향이 ↕ 3의 방향이 ←와 ↓인 경우 감시받는 영역은 다음과 같다.

# # 2 # 3
0 6 # 0 #
0 0 6 6 #
0 0 0 0 #

사무실의 크기와 상태, 그리고 CCTV의 정보가 주어졌을 때, CCTV의 방향을 적절히 정해서, 사각 지대의 최소 크기를 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 사무실의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에는 사무실 각 칸의 정보가 주어진다. 0은 빈 칸, 6은 벽, 1~5는 CCTV를 나타내고, 문제에서 설명한 CCTV의 종류이다. 

CCTV의 최대 개수는 8개를 넘지 않는다.

  • 출력

첫째 줄에 사각 지대의 최소 크기를 출력한다.

  • 예제 입력
4 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 6 0
0 0 0 0 0 0
6 6
0 0 0 0 0 0
0 2 0 0 0 0
0 0 0 0 6 0
0 6 0 0 2 0
0 0 0 0 0 0
0 0 0 0 0 5
6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
6 6
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 5 0 0
0 0 5 1 0 0
0 0 0 0 1 0
0 0 0 0 0 1
1 7
0 1 2 3 4 5 6
3 7
4 0 0 0 0 0 0
0 0 0 2 0 0 0
0 0 0 0 0 0 4
  • 예제 출력
20
15
6
2
0
0
  • 접근방식

CCTV마다 탐색 범위를 다르게 설정해서 해당 좌표들을 변경한다음에
dfs를 통해 사각지대를 더한다.

방향을 돌려가면서 경우의 수를 찾을때 %4(4방향)을 사용한다.

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

using namespace std;

const int dy[] = { -1,0,1,0 };
const int dx[] = { 0,1,0,-1 };

int n, m, _map[10][10], temp[10][10], result = 99999999;
vector<pair<int, int>> v;

bool CheckOver(int ny, int nx)
{
    if (ny < n && ny >= 0 && nx < m && nx >= 0 && _map[ny][nx] != 6)
    {
        return true;
    }
    return false;
}

vector<pair<int, int>> extendCCTV(int here, int direction)
{
    vector<pair<int, int>> _change;
    int y = v[here].first;
    int x = v[here].second;
    
    if (_map[y][x] == 1) // 1방향 카메라
    {
        while (1)
        {
            int ny = y + dy[direction];
            int nx = x + dx[direction];

            if (CheckOver(ny,nx))
            {
                if (_map[ny][nx] == 0)
                {
                    _map[ny][nx] = '#';
                    _change.push_back({ ny,nx });
                }
                y = ny;
                x = nx;
            }
            else
            {
                break;
            }
        }
    }
    else if (_map[y][x] == 2) // 2방향 앞뒤 카메라
    {
        for (int i = 0; i <= 2; i += 2)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    else if (_map[y][x] == 3) // 2방향  직각 카메라
    {
        for (int i = 0; i < 2; i++)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    else if (_map[y][x] == 4) // 3방향 카메라
    {
        for (int i = 0; i < 3; i++)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    else if (_map[y][x] == 5) // 4방향 카메라
    {
        for (int i = 0; i < 4; i++)
        {
            int _y = y;
            int _x = x;

            while (1)
            {
                int ny = _y + dy[(direction + i) % 4];
                int nx = _x + dx[(direction + i) % 4];

                if (CheckOver(ny, nx))
                {
                    if (_map[ny][nx] == 0)
                    {
                        _map[ny][nx] = '#';
                        _change.push_back({ ny,nx });
                    }
                    _y = ny;
                    _x = nx;
                }
                else
                {
                    break;
                }
            }
        }
    }
    return _change;
}

void dfs(int here)
{
    if (here == v.size())
    {
        int cnt = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                if (_map[i][j] == 0)
                {
                    cnt++;
                }
            }
        }
        result = min(cnt, result);
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        vector<pair<int, int>> _change = extendCCTV(here, i);
        dfs(here + 1);
        for (auto b : _change)
        {
            _map[b.first][b.second] = 0;
        }
    }
}

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

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> _map[i][j];
            if (_map[i][j] != 6 && _map[i][j] != 0)
            {
                v.push_back({ i,j });
            }
        }
    }

    dfs(0);
    cout << result;

    return 0;
}
 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 2170번 선 긋기  (0) 2024.03.26
[C++]/백준 17822번 원판 돌리기  (0) 2024.03.26
[C++]/백준 1912번 연속합  (0) 2024.03.26
[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
728x90
반응형
  • 문제

n개의 정수로 이루어진 임의의 수열이 주어진다. 우리는 이 중 연속된 몇 개의 수를 선택해서 구할 수 있는 합 중 가장 큰 합을 구하려고 한다. 단, 수는 한 개 이상 선택해야 한다.

예를 들어서 10, -4, 3, 1, 5, 6, -35, 12, 21, -1 이라는 수열이 주어졌다고 하자. 여기서 정답은 12+21인 33이 정답이 된다.

  • 입력

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

  • 출력

첫째 줄에 답을 출력한다.

  • 예제 입력
10
10 -4 3 1 5 6 -35 12 21 -1
10
2 1 -4 3 4 -4 6 5 -5 1
5
-1 -2 -3 -4 -5
  • 예제 출력
33
14
-1
  • 접근방식

구간을 더하면서 더한 수(sum)가 음수면은 더한 수(sum)을 버리고 계속 이어 나간다.

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

using namespace std;

int n, sum, a, result = -1001;

int main()
{
    cin >> n;

    for (int i = 0; i < n; i++)
    {
        cin >> a;
        sum += a;
        result = max(result, sum);
        if (sum < 0)
        {
            sum = 0;
        }
    }

    cout << result;

    return 0;
}
 

1912번: 연속합

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 17822번 원판 돌리기  (0) 2024.03.26
[C++]/백준 15683번 감시  (0) 2024.03.26
[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
728x90
반응형
  • 문제

고객이 두 종류의 피자 A와 B를 취급하는 피자가게에서 피자를 주문하고자 한다. <그림 1>과 같이 각 종류의 피자는 다양한 크기의 여러 개의 피자조각으로 나누어져 있다. 각 조각에 쓰여진 숫자는 피자조각의 크기를 나타낸다.

고객이 원하는 피자의 크기를 이야기하면, 피자가게에서는 한 종류의 피자를 2 조각 이상 판매할 때는 반드시 연속된 조각들을 잘라서 판매한다. 이때 판매한 피자조각의 크기 합이 주문한 크기가 되어야 한다. 판매한 피자조각은 모두 A종류이거나, 모두 B종류이거나, 또는 A와 B 종류가 혼합될 수 있다. 예를 들어서, <그림 1> 과 같이 잘라진 피자가 있을 때, 손님이 전체 크기가 7 인 피자를 주문하면, 피자 가게에서는 <그림2>와 같이 5 가지 방법으로 피자를 판매할 수 있다.

 

피자가게에서 손님이 원하는 크기의 피자를 판매하는 모든 방법의 가지 수를 계산하는 프로그램을 작성하시오

  • 입력

첫 번째 줄에는 손님이 구매하고자 하는 피자크기를 나타내는 2,000,000 이하의 자연수가 주어진다. 두 번째 줄에는 A, B 피자의 피자조각의 개수를 나타내 는 정수 m, n 이 차례로 주어진다 (3 ≤ m, n ≤ 1000). 세 번째 줄부터 차례로 m 개의 줄에는 피자 A의 미리 잘라진 피자조각의 크기를 나타내는 정수가 주어진다. 그 다음 n 개의 줄에는 차례로 피자B의 미리 잘라진 피자조각의 크기를 나타내는 정수가 주어진다. 각 종류의 피자조각의 크기는 시계방향으로 차례로 주어지며, 각 피자 조각의 크기는 1000 이하의 자연수이다.

  • 출력

첫째 줄에는 피자를 판매하는 방법의 가지 수를 나타내는 정수를 출력한다. 피자를 판매하는 방법이 없는 경우에는 숫자 0을 출력한다.

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

누적합을 이용해서 푸는데
a에서 만들수 있는 경우의 수, b에서 만들수 있는 경우의 수, a와 b에서 꺼내서 만들수 있는 경우의 수를 더하면 된다.

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

using namespace std;

int wantSize, n, m, a[1004], b[1004], psum_a[2008], psum_b[2008], result;
map<int, int> cnt_a, cnt_b;

void make(int n, int psum[], map<int, int>& cnt)
{
    for (int i = 1; i <= n; i++)
    {
        for (int j = i; j <= n + i - 1; j++)
        {
            int sum = psum[j] - psum[j - i];
            cnt[sum]++;
            if (i == n)  break;
        }
    }
    return;
}

int main()
{

    cin >> wantSize >> n >> m;

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

    for (int i = n + 1; i <= 2 * n; i++)
    {
        psum_a[i] = psum_a[i - 1] + a[i - n];
    }

    for (int i = 1; i <= m; i++)
    {
        cin >> b[i];
        psum_b[i] = psum_b[i - 1] + b[i];
    }

    for (int i = m + 1; i <= 2 * m; i++)
    {
        psum_b[i] = psum_b[i - 1] + b[i - m];
    }

    make(n, psum_a, cnt_a);
    make(m, psum_b, cnt_b);

    for (int i = 1; i < wantSize; i++)
    {
        result += cnt_a[wantSize - i] * cnt_b[i];
    }

    result += cnt_a[wantSize];
    result += cnt_b[wantSize];

    cout << result;

    return 0;
}
 

2632번: 피자판매

첫 번째 줄에는 손님이 구매하고자 하는 피자크기를 나타내는 2,000,000 이하의 자연수가 주어진다. 두 번째 줄에는 A, B 피자의 피자조각의 개수를 나타내 는 정수 m, n 이 차례로 주어진다 (3 ≤ m, n

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 15683번 감시  (0) 2024.03.26
[C++]/백준 1912번 연속합  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
728x90
반응형
  • 문제

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다. 칸에는 상어가 최대 한 마리 들어있을 수 있다. 상어는 크기와 속도를 가지고 있다.

낚시왕은 처음에 1번 열의 한 칸 왼쪽에 있다. 다음은 1초 동안 일어나는 일이며, 아래 적힌 순서대로 일어난다. 낚시왕은 가장 오른쪽 열의 오른쪽 칸에 이동하면 이동을 멈춘다.

  1. 낚시왕이 오른쪽으로 한 칸 이동한다.
  2. 낚시왕이 있는 열에 있는 상어 중에서 땅과 제일 가까운 상어를 잡는다. 상어를 잡으면 격자판에서 잡은 상어가 사라진다.
  3. 상어가 이동한다.

상어는 입력으로 주어진 속도로 이동하고, 속도의 단위는 칸/초이다. 상어가 이동하려고 하는 칸이 격자판의 경계를 넘는 경우에는 방향을 반대로 바꿔서 속력을 유지한채로 이동한다.

왼쪽 그림의 상태에서 1초가 지나면 오른쪽 상태가 된다. 상어가 보고 있는 방향이 속도의 방향, 왼쪽 아래에 적힌 정수는 속력이다. 왼쪽 위에 상어를 구분하기 위해 문자를 적었다.

상어가 이동을 마친 후에 한 칸에 상어가 두 마리 이상 있을 수 있다. 이때는 크기가 가장 큰 상어가 나머지 상어를 모두 잡아먹는다.

낚시왕이 상어 낚시를 하는 격자판의 상태가 주어졌을 때, 낚시왕이 잡은 상어 크기의 합을 구해보자.

  • 입력

첫째 줄에 격자판의 크기 R, C와 상어의 수 M이 주어진다. (2 ≤ R, C ≤ 100, 0 ≤ M ≤ R×C)

둘째 줄부터 M개의 줄에 상어의 정보가 주어진다. 상어의 정보는 다섯 정수 r, c, s, d, z (1 ≤ r ≤ R, 1 ≤ c ≤ C, 0 ≤ s ≤ 1000, 1 ≤ d ≤ 4, 1 ≤ z ≤ 10000) 로 이루어져 있다. (r, c)는 상어의 위치, s는 속력, d는 이동 방향, z는 크기이다. d가 1인 경우는 위, 2인 경우는 아래, 3인 경우는 오른쪽, 4인 경우는 왼쪽을 의미한다.

두 상어가 같은 크기를 갖는 경우는 없고, 하나의 칸에 둘 이상의 상어가 있는 경우는 없다.

  • 출력

낚시왕이 잡은 상어 크기의 합을 출력한다.

  • 예제 입력
4 6 8
4 1 3 3 8
1 3 5 2 9
2 4 8 4 1
4 5 0 1 4
3 3 1 2 7
1 5 8 4 3
3 6 2 1 2
2 2 2 3 5
100 100 0
4 5 4
4 1 3 3 8
1 3 5 2 9
2 4 8 4 1
4 5 0 1 4
2 2 4
1 1 1 1 1
2 2 2 2 2
1 2 1 2 3
2 1 2 1 4
  • 예제 출력
22
0
22
4
  • 접근방식

1. 사람이 움직이면서 상어를 잡는 처리
2. 상어가 움직이면서 상어를 먹는 처리
3. 벽에 부딪히면 방향 전환

방향이 1부터 시작하므로 {0,0,0,1,-1} 같이 크기가 5인 dx dy 필요
좌표도 1부터 시작하므로 1부터 시작하거나 -1을 하여 0으로 맞춰줘야함
temp를 통해서 상어가 계속 이동하는 것을 구현해서 현재 맵에 다시 덮어주기

  • 코드
#include <iostream>
#include <algorithm>
#include <string.h>

using namespace std;

struct Shark
{
    int x, y, s, z, dir, death;
}a[104 * 104];

const int dx[] = { 0, 0, 0, 1, -1 };
const int dy[] = { 0, -1, 1, 0, 0 };

int R, C, M, result, _map[104][104], temp[104][104];

int main()
{
    cin >> R >> C >> M;

    for (int i = 1; i <= M; i++)
    {
        cin >> a[i].y >> a[i].x >> a[i].s >> a[i].dir >> a[i].z;
        a[i].y -= 1;
        a[i].x -= 1;
        _map[a[i].y][a[i].x] = i;
    }

    for (int t = 0; t < C; t++)
    {
        for (int y = 0; y < R; y++) // 이동하면서 상어 잡는 처리
        {
            if (_map[y][t])
            {
                a[_map[y][t]].death = 1;
                result += a[_map[y][t]].z;
                _map[y][t] = 0;
                break;
            }
        }

        memset(temp, 0, sizeof(temp));

        for (int i = 1; i <= M; i++) // 상어가 움직이는 처리
        {
            if (a[i].death) continue;

            int _y = a[i].y;
            int _x = a[i].x;
            int s = a[i].s;
            int d = a[i].dir;
            int ny, nx;

            while (1) // 벽에 부딪히면 방향 전환
            {
                ny = _y + s * dy[d];
                nx = _x + s * dx[d];
                if (nx < C && ny < R && ny >= 0 && nx >= 0) break;
                if (d == 1 && ny < 0)
                {
                    s -= _y;
                    _y = 0;
                    d = 2;
                }
                else if (d == 2 && ny >= R)
                {
                    s -= R - 1 - _y;
                    _y = R - 1;
                    d = 1;
                }
                else if (d == 3 && nx >= C)
                {
                    s -= C - 1 - _x;
                    _x = C - 1;
                    d = 4;
                }
                else if (d == 4 && nx < 0)
                {
                    s -= _x;
                    _x = 0;
                    d = 3;
                }
            }
            if (temp[ny][nx])
            {
                if (a[temp[ny][nx]].z < a[i].z)
                { 
                    a[temp[ny][nx]].death = 1;
                    temp[ny][nx] = i;
                }
                else
                {
                    a[i].death = 1;
                }
            }
            else
            {
                temp[ny][nx] = i;
            }

            a[i].x = nx;
            a[i].y = ny;
            a[i].dir = d;
        }

        memcpy(_map, temp, sizeof(temp));

    }

    cout << result;

    return 0;
}
 

17143번: 낚시왕

낚시왕이 상어 낚시를 하는 곳은 크기가 R×C인 격자판으로 나타낼 수 있다. 격자판의 각 칸은 (r, c)로 나타낼 수 있다. r은 행, c는 열이고, (R, C)는 아래 그림에서 가장 오른쪽 아래에 있는 칸이다.

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 1912번 연속합  (0) 2024.03.26
[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
[C++]/백준 15662번 톱니바퀴 (2)  (0) 2024.03.25
728x90
반응형
  • 문제

N개의 수로 이루어진 수열 A1, A2, ..., AN이 주어진다. 또, 수와 수 사이에 끼워넣을 수 있는 N-1개의 연산자가 주어진다. 연산자는 덧셈(+), 뺄셈(-), 곱셈(×), 나눗셈(÷)으로만 이루어져 있다.

우리는 수와 수 사이에 연산자를 하나씩 넣어서, 수식을 하나 만들 수 있다. 이때, 주어진 수의 순서를 바꾸면 안 된다.

예를 들어, 6개의 수로 이루어진 수열이 1, 2, 3, 4, 5, 6이고, 주어진 연산자가 덧셈(+) 2개, 뺄셈(-) 1개, 곱셈(×) 1개, 나눗셈(÷) 1개인 경우에는 총 60가지의 식을 만들 수 있다. 예를 들어, 아래와 같은 식을 만들 수 있다.

  • 1+2+3-4×5÷6
  • 1÷2+3+4-5×6
  • 1+2÷3×4-5+6
  • 1÷2×3-4+5+6

식의 계산은 연산자 우선 순위를 무시하고 앞에서부터 진행해야 한다. 또, 나눗셈은 정수 나눗셈으로 몫만 취한다. 음수를 양수로 나눌 때는 C++14의 기준을 따른다. 즉, 양수로 바꾼 뒤 몫을 취하고, 그 몫을 음수로 바꾼 것과 같다. 이에 따라서, 위의 식 4개의 결과를 계산해보면 아래와 같다.

  • 1+2+3-4×5÷6 = 1
  • 1÷2+3+4-5×6 = 12
  • 1+2÷3×4-5+6 = 5
  • 1÷2×3-4+5+6 = 7

N개의 수와 N-1개의 연산자가 주어졌을 때, 만들 수 있는 식의 결과가 최대인 것과 최소인 것을 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱셈(×)의 개수, 나눗셈(÷)의 개수이다.

  • 출력

첫째 줄에 만들 수 있는 식의 결과의 최댓값을, 둘째 줄에는 최솟값을 출력한다. 연산자를 어떻게 끼워넣어도 항상 -10억보다 크거나 같고, 10억보다 작거나 같은 결과가 나오는 입력만 주어진다. 또한, 앞에서부터 계산했을 때, 중간에 계산되는 식의 결과도 항상 -10억보다 크거나 같고, 10억보다 작거나 같다.

  • 예제 입력
2
5 6
0 0 1 0
3
3 4 5
1 0 1 0
6
1 2 3 4 5 6
2 1 1 1
  • 예제 출력
30
30
35
17
54
-24
  • 접근방식

연산자의 갯수를 하나씩 줄여가면서 연산자의 수가 모두 떨어질 때 까지 계산하면 된다.

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

using namespace std;

int n, a[12], b[4], p, minu, mult, divi, max_result = -1000000001, min_result = 1000000001;

void calculate(int idx, int cur, int plus, int minus, int mul, int div)
{
	if (idx == n - 1)
	{
		max_result = max(cur, max_result);
		min_result = min(min_result, cur);
		return;
	}
	if (plus)	calculate(idx + 1, cur + a[idx + 1], plus - 1, minus, mul, div);
	if (minus)	calculate(idx + 1, cur - a[idx + 1], plus, minus - 1, mul, div);
	if (mul)	 calculate(idx + 1, cur * a[idx + 1], plus, minus, mul - 1, div);
	if (div) calculate(idx + 1, cur / a[idx + 1], plus, minus, mul, div - 1);
	return;
}

int main()
{
	cin >> n;

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

	cin >> p >> minu >> mult >> divi;

	calculate(0, a[0], p, minu, mult, divi);

	cout << max_result << endl << min_result;

    return 0;
}
 

14888번: 연산자 끼워넣기

첫째 줄에 수의 개수 N(2 ≤ N ≤ 11)가 주어진다. 둘째 줄에는 A1, A2, ..., AN이 주어진다. (1 ≤ Ai ≤ 100) 셋째 줄에는 합이 N-1인 4개의 정수가 주어지는데, 차례대로 덧셈(+)의 개수, 뺄셈(-)의 개수, 곱

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 2632번 피자판매  (0) 2024.03.26
[C++]/백준 17143번 낚시왕  (0) 2024.03.26
[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
[C++]/백준 15662번 톱니바퀴 (2)  (0) 2024.03.25
[C++]/백준 17406번 배열 돌리기 4  (0) 2024.03.25
728x90
반응형
  • 문제

어젯밤 겨울 캠프 장소에서 월드 본원까지 이어지는, 흙으로 된 비밀길 위에 폭우가 내려서 N(1 ≤ N ≤ 10,000)개의 물웅덩이가 생겼다. 월드학원은 물웅덩이를 덮을 수 있는 길이가 L(1 ≤ L ≤ 1,000,000)인 널빤지들을 충분히 가지고 있어서, 이들로 다리를 만들어 물웅덩이들을 모두 덮으려고 한다. 물웅덩이들의 위치와 크기에 대한 정보가 주어질 때, 모든 물웅덩이들을 덮기 위해 필요한 널빤지들의 최소 개수를 구하여라.

  • 입력

첫째 줄에 두 정수 N과 L이 들어온다.

둘째 줄부터 N+1번째 줄까지 총 N개의 줄에 각각의 웅덩이들의 정보가 주어진다. 웅덩이의 정보는 웅덩이의 시작 위치와 끝 위치로 이루어진다. 각 위치는 0 이상 1,000,000,000 이하의 정수이다. 입력으로 주어지는 웅덩이는 겹치지 않는다.

  • 출력

첫째 줄에 모든 물웅덩이들을 덮기 위해 필요한 널빤지들의 최소 개수를 출력한다.

  • 예제 입력
3 3
1 6
13 17
8 12
  • 예제 출력
5
  • 접근방식

1. 널빤지를 어떻게 채울 것인가?
2. 겹치는 부분은 하나로 처리

 

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

using namespace std;

int n, l, idx, plank, result;
int a, b;
vector<pair<int, int>> v;

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

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

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

    for (int i = 0; i < n; i++)
    {
        if (v[i].second <= idx)  continue; // 널빤지 끝 부분 index
        if (idx < v[i].first)
        {
            plank = (v[i].second - v[i].first) / l + ((v[i].second - v[i].first) % l ? 1 : 0);
            idx = v[i].first + plank * l;
        }
        else // 웅덩이의 크기가 더 큰 경우
        {
            plank = (v[i].second - idx) / l + ((v[i].second - idx) % l ? 1 : 0);
            idx = idx + plank * l;
        }
        result += plank;
    }

    cout << result;

    return 0;
}
 

1911번: 흙길 보수하기

어젯밤 겨울 캠프 장소에서 월드 본원까지 이어지는, 흙으로 된 비밀길 위에 폭우가 내려서 N(1 ≤ N ≤ 10,000)개의 물웅덩이가 생겼다. 월드학원은 물웅덩이를 덮을 수 있는 길이가 L(1 ≤ L ≤ 1,000

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 17143번 낚시왕  (0) 2024.03.26
[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
[C++]/백준 15662번 톱니바퀴 (2)  (0) 2024.03.25
[C++]/백준 17406번 배열 돌리기 4  (0) 2024.03.25
[C++]/백준 3190번 뱀  (1) 2024.03.25
728x90
반응형
  • 문제

총 8개의 톱니를 가지고 있는 톱니바퀴 T개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴가 1번, 그 오른쪽은 2번, ..., 가장 오른쪽 톱니바퀴는 T번이다. 아래 그림은 T가 4인 경우이다.

이때, 톱니바퀴를 총 K번 회전시키려고 한다. 톱니바퀴의 회전은 한 칸을 기준으로 한다. 회전은 시계 방향과 반시계 방향이 있고, 아래 그림과 같이 회전한다.

톱니바퀴를 회전시키려면, 회전시킬 톱니바퀴와 회전시킬 방향을 결정해야 한다. 톱니바퀴가 회전할 때, 서로 맞닿은 극에 따라서 옆에 있는 톱니바퀴를 회전시킬 수도 있고, 회전시키지 않을 수도 있다. 톱니바퀴 A를 회전할 때, 그 옆에 있는 톱니바퀴 B와 서로 맞닿은 톱니의 극이 다르다면, B는 A가 회전한 방향과 반대방향으로 회전하게 된다. 예를 들어, 아래와 같은 경우를 살펴보자.

두 톱니바퀴의 맞닿은 부분은 초록색 점선으로 묶여있는 부분이다. 여기서, 3번 톱니바퀴를 반시계 방향으로 회전했다면, 4번 톱니바퀴는 시계 방향으로 회전하게 된다. 2번 톱니바퀴는 맞닿은 부분이 S극으로 서로 같기 때문에, 회전하지 않게 되고, 1번 톱니바퀴는 2번이 회전하지 않았기 때문에, 회전하지 않게 된다. 따라서, 아래 그림과 같은 모양을 만들게 된다.

위와 같은 상태에서 1번 톱니바퀴를 시계 방향으로 회전시키면, 2번 톱니바퀴가 반시계 방향으로 회전하게 되고, 2번이 회전하기 때문에, 3번도 동시에 시계 방향으로 회전하게 된다. 4번은 3번이 회전하지만, 맞닿은 극이 같기 때문에 회전하지 않는다. 따라서, 아래와 같은 상태가 된다.

톱니바퀴 T개의 초기 상태와 톱니바퀴를 회전시킨 방법이 주어졌을 때, 최종 톱니바퀴의 상태를 구하는 프로그램을 작성하시오.

  • 입력

첫째 줄에 톱니바퀴의 개수 T (1 ≤ T ≤ 1,000)가 주어진다. 

둘째 줄부터 T개의 줄에 톱니바퀴의 상태가 가장 왼쪽 톱니바퀴부터 순서대로 주어진다. 상태는 8개의 정수로 이루어져 있고, 12시방향부터 시계방향 순서대로 주어진다. N극은 0, S극은 1로 나타나있다.

다음 줄에는 회전 횟수 K(1 ≤ K ≤ 1,000)가 주어진다. 다음 K개 줄에는 회전시킨 방법이 순서대로 주어진다. 각 방법은 두 개의 정수로 이루어져 있고, 첫 번째 정수는 회전시킨 톱니바퀴의 번호, 두 번째 정수는 방향이다. 방향이 1인 경우는 시계 방향이고, -1인 경우는 반시계 방향이다.

  • 출력

총 K번 회전시킨 이후에 12시방향이 S극인 톱니바퀴의 개수를 출력한다.

  • 예제 입력
4
10101111
01111101
11001110
00000010
2
3 -1
1 1
4
11111111
11111111
11111111
11111111
3
1 1
2 1
3 1
4
10001011
10000011
01011011
00111101
5
1 1
2 1
3 1
4 1
1 -1
4
10010011
01010011
11100011
01010101
8
1 1
2 1
3 1
4 1
1 -1
2 -1
3 -1
4 -1
5
10010011
01010011
11100011
01010101
01010011
10
1 1
2 1
3 1
4 1
1 -1
2 -1
3 -1
4 -1
5 1
5 -1
  • 예제 출력
3
4
2
2
5
  • 접근방식

1. 오른쪽과 왼쪽이 어디까지 회전하는지 (=극이 같을때) 구하고
2. rotate를 한다 > 시계, 반시계 구현

오른쪽과 왼쪽이 어디까지 회전하는지를 볼때는 2번째와 6번째를 비교하면 된다.

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

using namespace std;

int t, k, result;
string s[1004];

void rotateGear(int pos, int dir)
{
    if (!dir)
    {
        rotate(s[pos].begin(), s[pos].begin() + 1, s[pos].end());
    }
    else
    {
        rotate(s[pos].begin(), s[pos].begin() + s[pos].size() - 1, s[pos].end());
    }
}

int findLeft(int pos)
{
    for (int i = pos; i >= 1; i--)
    {
        if (s[i][6] == s[i - 1][2]) // 왼쪽으로 비교
        {
            return i;
        }
    }
    return 0;
}

int findRight(int pos)
{
    for (int i = pos; i <= t - 2; i++)
    {
        if (s[i][2] == s[i + 1][6]) // 오른쪽으로 비교
        {
            return i;
        }
    }
    return t - 1;
}

int main()
{
    cin >> t;

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

    cin >> k;

    int a, b;

    for (int i = 0; i < k; i++)
    {
        cin >> a >> b;
        a--; // 0부터 시작하려고 빼기
        b = (b == -1 ? 0 : 1); // 반시계 0 시계 1
        int left_ = findLeft(a); // 왼쪽 방향으로 어디까지 회전해야 하는지
        int right_ = findRight(a); // 오른쪽 방향으로 어디까지 회전해야 하는지
        int cnt = 0;

        for (int pos = a; pos >= left_; pos--)
        {
            rotateGear(pos, cnt % 2 == 0 ? b : !b);
            cnt++;
        }
        cnt = 1;
        for (int pos = a + 1; pos <= right_; pos++)
        {
            rotateGear(pos, cnt % 2 == 0 ? b : !b);
            cnt++;
        }
    }

    for (int i = 0; i < t; i++)
    {
        if (s[i][0] == '1')
        {
            result++;
        }
    }

    cout << result;

    return 0;
}
 

15662번: 톱니바퀴 (2)

총 8개의 톱니를 가지고 있는 톱니바퀴 T개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 14888번 연산자 끼워넣기  (1) 2024.03.25
[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
[C++]/백준 17406번 배열 돌리기 4  (0) 2024.03.25
[C++]/백준 3190번 뱀  (1) 2024.03.25
[C++]/백준 12100번 2048(Easy)  (0) 2024.03.21
728x90
반응형
  • 문제

크기가 N×M 크기인 배열 A가 있을때, 배열 A의 값은 각 행에 있는 모든 수의 합 중 최솟값을 의미한다. 배열 A가 아래와 같은 경우 1행의 합은 6, 2행의 합은 4, 3행의 합은 15이다. 따라서, 배열 A의 값은 4이다.

1 2 3
2 1 1
4 5 6

배열은 회전 연산을 수행할 수 있다. 회전 연산은 세 정수 (r, c, s)로 이루어져 있고, 가장 왼쪽 윗 칸이 (r-s, c-s), 가장 오른쪽 아랫 칸이 (r+s, c+s)인 정사각형을 시계 방향으로 한 칸씩 돌린다는 의미이다. 배열의 칸 (r, c)는 r행 c열을 의미한다.

예를 들어, 배열 A의 크기가 6×6이고, 회전 연산이 (3, 4, 2)인 경우에는 아래 그림과 같이 회전하게 된다.

A[1][1]   A[1][2] → A[1][3] → A[1][4] → A[1][5] → A[1][6]
             ↑                                       ↓
A[2][1]   A[2][2]   A[2][3] → A[2][4] → A[2][5]   A[2][6]
             ↑         ↑                   ↓         ↓
A[3][1]   A[3][2]   A[3][3]   A[3][4]   A[3][5]   A[3][6]
             ↑         ↑                   ↓         ↓
A[4][1]   A[4][2]   A[4][3] ← A[4][4] ← A[4][5]   A[4][6]
             ↑                                       ↓
A[5][1]   A[5][2] ← A[5][3] ← A[5][4] ← A[5][5] ← A[5][6]

A[6][1]   A[6][2]   A[6][3]   A[6][4]   A[6][5]   A[6][6]

회전 연산이 두 개 이상이면, 연산을 수행한 순서에 따라 최종 배열이 다르다.

다음은 배열 A의 크기가 5×6이고, 회전 연산이 (3, 4, 2), (4, 2, 1)인 경우의 예시이다.

배열 A에 (3, 4, 2), (4, 2, 1) 순서로 연산을 수행하면 배열 A의 값은 12, (4, 2, 1), (3, 4, 2) 순서로 연산을 수행하면 15 이다.

배열 A와 사용 가능한 회전 연산이 주어졌을 때, 배열 A의 값의 최솟값을 구해보자. 회전 연산은 모두 한 번씩 사용해야 하며, 순서는 임의로 정해도 된다.

  • 입력

첫째 줄에 배열 A의 크기 N, M, 회전 연산의 개수 K가 주어진다.

둘째 줄부터 N개의 줄에 배열 A에 들어있는 수 A[i][j]가 주어지고, 다음 K개의 줄에 회전 연산의 정보 r, c, s가 주어진다.

  • 출력

배열 A의 값의 최솟값을 출력한다.

  • 예제 입력
5 6 2
1 2 3 2 5 6
3 8 7 2 1 3
8 2 3 1 4 5
3 4 5 1 1 1
9 3 2 1 4 3
3 4 2
4 2 1
  • 예제 출력
12
  • 접근방식

1. 먼저, 돌려야 할 영역을 뽑고
2. 돌리기만 하면 된다.

돌릴 때는 rotate함수를 사용하고 rbegin을 사용하면 된다. (12345678 > 23456781)
돌릴 때 꼭지점을 정해주고 돌리면 더 쉬울것 같아서 꼭지점을 정해 주었다. > 꼭지점에 도달하면 돌려서 배열 정보 저장
순열을 사용해서 돌려가면서 행의 가장 적은 값을 찾으면 된다.

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

using namespace std;

const int dy[] = { 0,1,0,-1 };
const int dx[] = { 1,0,-1,0 };
int n, m, k, a[104][104], temp[104][104], visited[104][104], sy, sx, ey, ex, r, c, s, direction, result = 99999999;
vector<pair<int, int>> v;
vector<int> v_idx;
vector<tuple<int, int, int>> rotateV;

void directionChange(int y, int x, int first)
{
    if (!first && y == sy && x == sx)    direction++;
    if (!first && y == sy && x == ex)    direction++;
    if (!first && y == ey && x == ex)    direction++;
    if (!first && y == ey && x == sx)    direction++;

    int ny = y + dy[direction];
    int nx = x + dx[direction];
    if (visited[ny][nx]) return;
    visited[ny][nx] = 1;
    v.push_back({ ny,nx });
    directionChange(ny, nx, 0);
}

void rotateAll(int y, int x, int cnt)
{
    for (int i = 1; i <= cnt; i++)
    {
        sy = y - 1 * i;
        sx = x - 1 * i;
        ey = y + 1 * i;
        ex = x + 1 * i;
        v.clear();
        direction = 0;
        memset(visited, 0, sizeof(visited));
        visited[sy][sx] = 1;
        v.push_back({ sy,sx }); // 돌려야 할 것 뽑아내기
        directionChange(sy, sx, 1);

        vector<int> v2;
        for (pair<int, int> c : v)
        {
            v2.push_back(temp[c.first][c.second]);
        }
        rotate(v2.rbegin(), v2.rbegin() + 1, v2.rend());
        for (int i = 0; i < v.size(); i++)
        {
            temp[v[i].first][v[i].second] = v2[i];
        }
    }
}

int min_rowSum()
{
    for (int i : v_idx)
    {
        rotateAll(get<0>(rotateV[i]), get<1>(rotateV[i]), get<2>(rotateV[i]));
    }
    int tempResult = 99999999;
    for (int i = 0; i < n; i++)
    {
        int cnt = 0;
        for (int j = 0; j < m; j++)
        {
            cnt += temp[i][j];
        }
        tempResult = min(tempResult, cnt);
    }
    return tempResult;
}

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

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

    for (int i = 0; i < k; i++)
    {
        cin >> r >> c >> s;
        r--; // 0부터 시작하려고 뺌
        c--;
        rotateV.push_back({ r,c,s });
        v_idx.push_back(i);
    }
    do
    {
        memcpy(temp, a, sizeof(temp));
        result = min(result, min_rowSum());

    } while (next_permutation(v_idx.begin(), v_idx.end()));

    cout << result;

    return 0;
}
 

17406번: 배열 돌리기 4

크기가 N×M 크기인 배열 A가 있을때, 배열 A의 값은 각 행에 있는 모든 수의 합 중 최솟값을 의미한다. 배열 A가 아래와 같은 경우 1행의 합은 6, 2행의 합은 4, 3행의 합은 15이다. 따라서, 배열 A의

www.acmicpc.net

 

728x90
반응형

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

[C++]/백준 1911번 흙길 보수하기  (0) 2024.03.25
[C++]/백준 15662번 톱니바퀴 (2)  (0) 2024.03.25
[C++]/백준 3190번 뱀  (1) 2024.03.25
[C++]/백준 12100번 2048(Easy)  (0) 2024.03.21
[C++]/백준 17144번 미세먼지 안녕!  (0) 2024.03.20

+ Recent posts