728x90

백준 CPP 공부 2025.05.17
10814번 나이순 정렬

1. 문제
온라인 저지에 가입한 사람들의 나이와 이름이 가입한 순서대로 주어진다. 
이때, 회원들을 나이가 증가하는 순으로, 
나이가 같으면 먼저 가입한 사람이 앞에 오는 순서로 정렬하는 프로그램을 작성하시오.

2. 입력
첫째 줄에 온라인 저지 회원의 수 N이 주어진다. (1 ≤ N ≤ 100,000)

둘째 줄부터 N개의 줄에는 각 회원의 나이와 이름이 공백으로 구분되어 주어진다. 
나이는 1보다 크거나 같으며, 200보다 작거나 같은 정수이고, 
이름은 알파벳 대소문자로 이루어져 있고, 길이가 100보다 작거나 같은 문자열이다. 
입력은 가입한 순서로 주어진다.

3. 출력
첫째 줄부터 총 N개의 줄에 걸쳐 온라인 저지 회원을 나이 순, 
나이가 같으면 가입한 순으로 한 줄에 한 명씩 나이와 이름을 공백으로 구분해 출력한다.

4. 문제 풀이
1) STD vector 와 구조체 활용

stable_sort의 경우
같은 값(키)을 가진 원소들의 상대적인 순서를 유지하면서 정렬하는 알고리즘으로서
해당 문제에 적합하며, 가입 시기를 따로 생각하지 않아도 된다.
>> 코드 1

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

struct Member {
    int age;
    int idx;
    string name;
};

bool compare(const Member& a, const Member& b) {
    return a.age < b.age;
}

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

    vector<Member> members;
    for (int i = 0; i < n; ++i) {
        int age;
        string name;
        cin >> age >> name;
        members.push_back({age, i, name});
    }

    stable_sort(members.begin(), members.end(), compare);

    for (const auto& m : members) {
        cout << m.age << " " << m.name << '\n';
    }

    return 0;
}




2) STD list 와 클래스 활용 
listing 클래스를 생성해서 나이, 가입시기, 이름을 저장하고,
이를 list 연결리스트 구조를 이용하여 sort로 정렬하였다.

>>코드 2

#include <iostream>
#include <list>
#include <string>
using namespace std;

class listing {
    int age;
    int idx;
    string name;
public:
    listing(int age = 1, int idx = 1, string name = "KIM") {
        this->age = age;
        this->idx = idx;
        this->name = name;
    }
    ~listing() {}

    int getage() const { return age; }
    int getidx() const { return idx; }
    string getname() const { return name; }
};

bool compare(const listing &A, const listing &B) {
    if (A.getage() == B.getage()) return A.getidx() < B.getidx();
    else return A.getage() < B.getage();
}

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

    list<listing> OnlineJudge;
    for (int i = 0; i < n; i++) {
        int age;
        string name;
        cin >> age >> name;
        OnlineJudge.push_back(listing(age, i, name));
    }

    OnlineJudge.sort(compare);

    for (auto it = OnlineJudge.begin(); it != OnlineJudge.end(); it++) {
        cout << it->getage() <<  " " << it->getname() << endl;
    }

}



5. 문제 링크
https://www.acmicpc.net/problem/10814

728x90
728x90

백준 CPP 공부 2025.05.16
1181번 단어 정렬

1. 문제
알파벳 소문자로 이루어진 N개의 단어가 들어오면 
아래와 같은 조건에 따라 정렬하는 프로그램을 작성하시오.

1) 길이가 짧은 것부터
2) 길이가 같으면 사전 순으로

단, 중복된 단어는 하나만 남기고 제거해야 한다.

3. 입력
첫째 줄에 단어의 개수 N이 주어진다. (1 ≤ N ≤ 20,000) 
둘째 줄부터 N개의 줄에 걸쳐 알파벳 소문자로 이루어진 단어가 한 줄에 하나씩 주어진다. 
주어지는 문자열의 길이는 50을 넘지 않는다.

3. 출력
조건에 따라 정렬하여 단어들을 출력한다.

4. 문제 풀이

#include <iostream>
#include <list>
#include <string>
using namespace std;

// 문자 비교 기준 함수 작성
bool wordcompare(string A, string B){
if (A.length() == B.length()) {
return A < B;
}
else {
return A.length() < B.length();
}
}

int main(){
    int n;
    cin >> n;
    
    list<string> word;
    for (int i = 0; i<n; i++){
        string str;
        cin >> str;
        word.push_back(str);
    }
    
    word.sort(wordcompare); // 문자 wordcompare에 맞게 정렬
    word.unique(); // 문자 중복 제거
    
    for (auto it = word.begin(); it != word.end(); it++){
        cout << *it << endl;
    }
    
    return 0;
}



5. 문제 링크
https://www.acmicpc.net/problem/1181

728x90
728x90

백준 CPP 공부 2025.05.14
10845번 큐 (실버 4)

1. 문제
정수를 저장하는 큐를 구현한 다음, 
입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.

명령은 총 여섯 가지이다.

- push X: 정수 X를 큐에 넣는 연산이다.
- pop: 큐에서 가장 앞에 있는 정수를 빼고, 그 수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.
- size: 큐에 들어있는 정수의 개수를 출력한다.
- empty: 큐가 비어있으면 1, 아니면 0을 출력한다.
- front: 큐의 가장 앞에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.
- back: 큐의 가장 뒤에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.

2. 입력
첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 
둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 
주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 
문제에 나와있지 않은 명령이 주어지는 경우는 없다.

3. 출력
출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.

4. 문제 풀이
#include <queue>에서 지원하는 pop이 해당 값을 반환하지 않는다는 점만 유의하자.

>>코드

#include <iostream>
#include <queue>
#include <string>
using namespace std;

int main(){
    queue<int> Q;
    
    int n;
    cin  >> n;
    
    for (int i = 0; i < n; i++){
        string opr;
        cin >> opr;
        
        if (opr == "push"){
            int num;
            cin >> num;
            Q.push(num);
        }
        else if (opr == "pop"){
            if (Q.empty()) cout << -1 << endl;
            else {
                cout << Q.front() << endl;
                Q.pop();
            }
        }
        else if (opr == "size"){
            cout << Q.size() << endl;
        }
        else if (opr == "empty"){
            cout << Q.empty() << endl;
        }
        else if (opr == "front"){
            if (Q.empty()) cout << -1 << endl;
            else cout << Q.front() << endl;
        }
        else if (opr == "back"){
            if (Q.empty()) cout << -1 << endl;
            else cout << Q.back() << endl;
        }
    }
}



5. 문제 링크
https://www.acmicpc.net/problem/10845

728x90
728x90

백준 파이썬 공부 2025.04.05
6064번 카잉 달력 (실버 1)

1. 문제
최근에 ICPC 탐사대는 남아메리카의 잉카 제국이 놀라운 문명을 지닌 카잉 제국을 토대로 하여 세워졌다는 사실을 발견했다. 
카잉 제국의 백성들은 특이한 달력을 사용한 것으로 알려져 있다. 

그들은 M과 N보다 작거나 같은 두 개의 자연수 x, y를 가지고 각 년도를 <x:y>와 같은 형식으로 표현하였다. 
그들은 이 세상의 시초에 해당하는 첫 번째 해를 <1:1>로 표현하고, 두 번째 해를 <2:2>로 표현하였다. 

<x:y>의 다음 해를 표현한 것을 <x':y'>이라고 하자. 
만일 x < M 이면 x' = x + 1이고, 그렇지 않으면 x' = 1이다. 
같은 방식으로 만일 y < N이면 y' = y + 1이고, 그렇지 않으면 y' = 1이다. 
<M:N>은 그들 달력의 마지막 해로서, 이 해에 세상의 종말이 도래한다는 예언이 전해 온다.

예를 들어, M = 10 이고 N = 12라고 하자. 
첫 번째 해는 <1:1>로 표현되고, 11번째 해는 <1:11>로 표현된다. 
<3:1>은 13번째 해를 나타내고, <10:12>는 마지막인 60번째 해를 나타낸다.

네 개의 정수 M, N, x와 y가 주어질 때, <M:N>이 카잉 달력의 마지막 해라고 하면 
<x:y>는 몇 번째 해를 나타내는지 구하는 프로그램을 작성하라.

2. 입력
입력 데이터는 표준 입력을 사용한다. 

입력은 T개의 테스트 데이터로 구성된다. 
입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 

각 테스트 데이터는 한 줄로 구성된다. 
각 줄에는 네 개의 정수 M, N, x와 y가 주어진다. 
(1 ≤ M, N ≤ 40,000, 1 ≤ x ≤ M, 1 ≤ y ≤ N) 
여기서 <M:N>은 카잉 달력의 마지막 해를 나타낸다.

3. 출력
출력은 표준 출력을 사용한다. 
각 테스트 데이터에 대해, 정수 k를 한 줄에 출력한다. 
여기서 k는 <x:y>가 k번째 해를 나타내는 것을 의미한다. 
만일 <x:y>에 의해 표현되는 해가 없다면, 즉, <x:y>가 유효하지 않은 표현이면, -1을 출력한다.

4. 문제 해설
이건 정수론에 대해 어느 정도 알아야 풀이가 가능한 문제이다.
단순히 <1:1> 에서 부터 브루트 포스로 계산하려고 할 시에는 시간초과 엔딩이 난다.

<x:y> 일때, 이는 <(해당 해) % M : (해당 해) % N> 으로 나타낼 수 있다.
그 말을 식으로 작성하면,
answer = M * A1(나눗셈의 몫1) + x = N * A2(나눗셈의 몫2) + y
answer - x = M * A1 >> (answer - x) % M == 0
answer - y = N * A2 >> (answer - y) % N == 0
이걸 이용해보자

일단 가능한 마지막 해는 M과 N의 최소 공배수이고,
이 값을 넘어가면 해당 x, y에 해당하는 해는 존재하지 않는다고 보면 된다.
즉 -1

그리고 초기값을 x로 설정해 놓고 M을 더해가며,
각 값 - y가 N으로 나누어 떨어지는지 검사를 해가면 된다.

>> 코드

import sys

# 멸망의 해(마지막 해)를 구하기 위한 최대공약수와 최소공배수 함수
# 최대 공약수 함수
def gcd(x, y):
    if y == 0:
        return x
    else:
        return gcd(y, x%y)

# 최소 공배수 함수
def lcm(x, y):
    return x * y / gcd(x, y)

# 계산 함수
def calculate(M, N, x, y):
    # 초기 시작 값 x로 시작
    answer = x
    # 마지막 해 M, N의 최소 공배수로 설정
    max_value = lcm(M, N)
    # 해당값 - y가 N으로 나누어 떨어질 때까지 M 더하기
    while answer <= max_value:
        if (answer - y) % N == 0:
            return answer
        answer += M
    return -1

T = int(sys.stdin.readline().strip())
for _ in range(T):
    M, N, x, y = map(int, sys.stdin.readline().strip().split())
    
    print(calculate(M, N, x, y))


5. 문제 링크
https://www.acmicpc.net/problem/6064

728x90
728x90

백준 파이썬 공부 2025.04.02
30804번 과일 탕후루 (실버 2)

1. 문제
은하는 긴 막대에 N개의 과일이 꽂혀있는 과일 탕후루를 만들었습니다. 
과일의 각 종류에는 1부터 9까지의 번호가 붙어있고, 
앞쪽부터 차례로 S_1, S_2, ..., S_N번 과일이 꽂혀있습니다. 
과일 탕후루를 다 만든 은하가 주문을 다시 확인해보니 
과일을 두 종류 이하로 사용해달라는 요청이 있었습니다.

탕후루를 다시 만들 시간이 없었던 은하는, 
막대의 앞쪽과 뒤쪽에서 몇 개의 과일을 빼서 두 종류 이하의 과일만 남기기로 했습니다. 
앞에서 a개, 뒤에서 b개의 과일을 빼면 S_{a+1}, S_{a+2}, ..., S_{N-b-1}, S_{N-b}번 과일, 
총 N-(a+b)개가 꽂혀있는 탕후루가 됩니다. (0 <= a, b, a+b < N) 

이렇게 만들 수 있는 과일을 두 종류 이하로 사용한 탕후루 중에서, 
과일의 개수가 가장 많은 탕후루의 과일 개수를 구하세요.

2. 입력
첫 줄에 과일의 개수 N이 주어집니다. (1 <= N <= 200,000) 
둘째 줄에 탕후루에 꽂힌 과일을 의미하는 N개의 정수 S_1, ..., S_N이 공백으로 구분되어 주어집니다. (1 <= S_i <= 9)

3. 출력
문제의 방법대로 만들 수 있는 과일을 두 종류 이하로 사용한 탕후루 중에서, 
과일의 개수가 가장 많은 탕후루의 과일 개수를 첫째 줄에 출력하세요.

4. 문제 풀이
투 포인터로 포인터 두개를 이동해가면서
두 포인터 사이의 과일 갯수를 확인하면서 최대의 길이를 검사하면 된다.

>>>코드

import sys

n = int(sys.stdin.readline().strip())
Tanghulu = list(map(int, sys.stdin.readline().strip().split()))

p1, p2 = 0, 0
length = 0
cnt = {}

while p2 < n:
    # p2 위치의 과일 갯수와 종류 갱신
    if Tanghulu[p2] in cnt:
        cnt[Tanghulu[p2]] += 1
    else:
        cnt[Tanghulu[p2]] = 1
    
    # cnt 의 길이 (과일의 종류)가 2개가 넘어가면 과일의 종류가 2개가 될 때까지
    while len(cnt) > 2:
        # p1 위치의 과일을 제거하면서
        cnt[Tanghulu[p1]] -= 1
        if cnt[Tanghulu[p1]] == 0:
            del cnt[Tanghulu[p1]]
        # p1을 이동
        p1 += 1
    # 최대 길이 갱신
    length = max(length, p2 - p1 + 1)
    p2 += 1
            
print(length)


5. 문제 링크
https://www.acmicpc.net/problem/30804

728x90
728x90

백준 파이썬 공부 2025.03.31
2805번 나무 자르기 (실버 2)

1. 문제
상근이는 나무 M미터가 필요하다. 
근처에 나무를 구입할 곳이 모두 망해버렸기 때문에, 정부에 벌목 허가를 요청했다. 
정부는 상근이네 집 근처의 나무 한 줄에 대한 벌목 허가를 내주었고, 
상근이는 새로 구입한 목재절단기를 이용해서 나무를 구할것이다.

목재절단기는 다음과 같이 동작한다. 
먼저, 상근이는 절단기에 높이 H를 지정해야 한다. 
높이를 지정하면 톱날이 땅으로부터 H미터 위로 올라간다. 
그 다음, 한 줄에 연속해있는 나무를 모두 절단해버린다. 
따라서, 높이가 H보다 큰 나무는 H 위의 부분이 잘릴 것이고, 낮은 나무는 잘리지 않을 것이다.
 
예를 들어, 한 줄에 연속해있는 나무의 높이가 20, 15, 10, 17이라고 하자. 
상근이가 높이를 15로 지정했다면, 나무를 자른 뒤의 높이는 15, 15, 10, 15가 될 것이고, 
상근이는 길이가 5인 나무와 2인 나무를 들고 집에 갈 것이다. (총 7미터를 집에 들고 간다) 
절단기에 설정할 수 있는 높이는 양의 정수 또는 0이다.

상근이는 환경에 매우 관심이 많기 때문에, 나무를 필요한 만큼만 집으로 가져가려고 한다. 
이때, 적어도 M미터의 나무를 집에 가져가기 위해서 절단기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하시오.

2. 입력
첫째 줄에 나무의 수 N과 상근이가 집으로 가져가려고 하는 나무의 길이 M이 주어진다. 
(1 ≤ N ≤ 1,000,000, 1 ≤ M ≤ 2,000,000,000)

둘째 줄에는 나무의 높이가 주어진다. 
나무의 높이의 합은 항상 M보다 크거나 같기 때문에, 
상근이는 집에 필요한 나무를 항상 가져갈 수 있다. 
높이는 1,000,000,000보다 작거나 같은 양의 정수 또는 0이다.

3. 출력
적어도 M미터의 나무를 집에 가져가기 위해서 절단기에 설정할 수 있는 높이의 최댓값을 출력한다.

4. 문제 풀이
전형적인 이분탐색 문제로서
start를 0 end를 max(tree) 즉 나무 중 가장 높이가 큰 나무 길이로 해놓고,
높이를 이분탐색 해가면서 자를 나무의 높이를 찾아가는 방식으로 실시한다.
다만, 필요한 나무의 길이인 m이 딱 나오지 않을 경우도 있기 때문에
필요한 나무의 길이보다 자른 총 나무의 길이가 길 때, 
자를 나무의 길이를 매번 저장해 놓으면서 갱신하는 방식을 필요로 한다.

>>> 코드

import sys

n, m = map(int, sys.stdin.readline().strip().split())
tree = list(map(int, sys.stdin.readline().strip().split()))

start = 0
end = max(tree)
while start <= end:
    mid = (end + start) // 2
    
    length = 0
    for i in range(n):
        if tree[i] > mid:
            length += tree[i] - mid
    if length >= m:
        result = mid
        start = mid + 1
    else:
        end = mid - 1

print(result)



5. 문제 링크
https://www.acmicpc.net/problem/2805

728x90
728x90

백준 파이썬 공부 2025.03.25
14500번 테트로미노 (골드 4)

1. 문제
폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 
다음과 같은 조건을 만족해야 한다.

1) 정사각형은 서로 겹치면 안 된다.
2) 도형은 모두 연결되어 있어야 한다.
3) 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다.

정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다.

테트로미노


아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 
종이는 1×1 크기의 칸으로 나누어져 있으며, 각각의 칸에는 정수가 하나 쓰여 있다.
테트로미노 하나를 적절히 놓아서 테트로미노가 놓인 칸에 쓰여 있는 수들의 합을 최대로 하는 프로그램을 작성하시오.

테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 
회전이나 대칭을 시켜도 된다.

2. 입력
첫째 줄에 종이의 세로 크기 N과 가로 크기 M이 주어진다. (4 ≤ N, M ≤ 500)

둘째 줄부터 N개의 줄에 종이에 쓰여 있는 수가 주어진다. 
i번째 줄의 j번째 수는 위에서부터 i번째 칸, 왼쪽에서부터 j번째 칸에 쓰여 있는 수이다. 
입력으로 주어지는 수는 1,000을 넘지 않는 자연수이다.

3. 출력
첫째 줄에 테트로미노가 놓인 칸에 쓰인 수들의 합의 최댓값을 출력한다.

4. 문제 풀이
처음에는 dfs와 백트래킹을 이용하여 문제를 풀고자 시도했다.
그러나 "ㅏ, ㅓ, ㅗ, ㅜ" 모양의 테트로미노는 dfs로 탐색이 불가했기에 문제를 풀지 못했다.

>> 코드 1. "ㅏ, ㅓ, ㅗ, ㅜ" 누락

import sys

def Tetro(y, x, cnt, value):
    global max_value
    if cnt == 4:
        max_value = max(max_value, value)
        return
    
    dx = [1, -1, 0, 0]
    dy = [0, 0, 1, -1]
    
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        
        if 0 <= nx < m and 0 <= ny < n and visited[ny][nx] == 0:
            visited[ny][nx] = 1
            Tetro(ny, nx, cnt+1, value + graph[ny][nx])
            visited[ny][nx] = 0
    
n, m = map(int, sys.stdin.readline().strip().split())

graph = []
for _ in range(n):
    arr = list(map(int, sys.stdin.readline().strip().split()))
    graph.append(arr)

max_value = 0
visited = [[0] * m for _ in range(n)]
for i in range(n):
    for j in range(m):
        visited[i][j] = 1
        Tetro(i, j, 1, graph[i][j])
        visited[i][j] = 0

print(max_value)



"ㅏ, ㅓ, ㅗ, ㅜ" 는 각 위치 기준으로 4개씩만 존재하기 때문에,
그냥 쌩으로 4개 값을 구해보고, global 최대값 비교로 최대값을 탐색했다

>> 정답 코드 (메모리 116820KB, 시간 760ms)

import sys

def Tetro(y, x, cnt, value):
    global max_value
    if cnt == 4:
        max_value = max(max_value, value)
        return
    
    dx = [1, -1, 0, 0]
    dy = [0, 0, 1, -1]
    
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        
        if 0 <= nx < m and 0 <= ny < n and visited[ny][nx] == 0:
            visited[ny][nx] = 1
            Tetro(ny, nx, cnt+1, value + graph[ny][nx])
            visited[ny][nx] = 0

def exception(y, x):
    global max_value
    if x - 1 >= 0 and x + 1 < m and y - 1 >= 0:
        max_value = max(max_value, graph[y][x] + graph[y][x+1] + graph[y][x-1] + graph[y-1][x])
    if x - 1 >= 0 and x + 1 < m and y + 1 < n: 
        # ㅜ
        max_value = max(max_value, graph[y][x] + graph[y][x+1] + graph[y][x-1] + graph[y+1][x])
    if y - 1 >= 0 and y + 1 < n and x - 1 >= 0:
        # ㅓ
        max_value = max(max_value, graph[y][x] + graph[y-1][x] + graph[y+1][x] + graph[y][x-1])
    if y - 1 >= 0 and y + 1 < n and x + 1 < m:
        # ㅏ
        max_value = max(max_value, graph[y][x] + graph[y-1][x] + graph[y+1][x] + graph[y][x+1])
            
n, m = map(int, sys.stdin.readline().strip().split())

graph = []
for _ in range(n):
    arr = list(map(int, sys.stdin.readline().strip().split()))
    graph.append(arr)

max_value = 0
visited = [[0] * m for _ in range(n)]
for i in range(n):
    for j in range(m):
        visited[i][j] = 1
        Tetro(i, j, 1, graph[i][j])
        visited[i][j] = 0
        exception(i, j)

print(max_value)



가지치기를 이용하면 더욱 빠르게 문제를 풀이가 가능하다고 한다.
가지치기를 쉽게 설명해보자면, 하는데 까지 해보고, 싹수가 안보이면 끝까지 계산안하고 접는 방식이라고 보면 된다.
싹수가 안보인다를 어떻게 판별하냐면,
현재 그래프에서 가장 큰 수를 구해놓고,
현재 남은 구간의 수 * 가장 큰수 + 현재까지의 합 이 현재 최대값보다 낮을 경우
무조건 안되기 때문에 그냥 도중에 접는 방식으로 시행하면 된다.

>> 코드 2. 가지치기 추가 (메모리 115344KB,  시간 180ms)

import sys

def Tetro(y, x, cnt, value):
    global max_value
    
    if value + (4-cnt) * max_num <= max_value:
        return
    
    if cnt == 4:
        max_value = max(max_value, value)
        return
    
    dx = [1, -1, 0, 0]
    dy = [0, 0, 1, -1]
    
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        
        if 0 <= nx < m and 0 <= ny < n and visited[ny][nx] == 0:
            visited[ny][nx] = 1
            Tetro(ny, nx, cnt+1, value + graph[ny][nx])
            visited[ny][nx] = 0

def exception(y, x):
    global max_value
    if x - 1 >= 0 and x + 1 < m and y - 1 >= 0:
        max_value = max(max_value, graph[y][x] + graph[y][x+1] + graph[y][x-1] + graph[y-1][x])
    if x - 1 >= 0 and x + 1 < m and y + 1 < n: 
        # ㅜ
        max_value = max(max_value, graph[y][x] + graph[y][x+1] + graph[y][x-1] + graph[y+1][x])
    if y - 1 >= 0 and y + 1 < n and x - 1 >= 0:
        # ㅓ
        max_value = max(max_value, graph[y][x] + graph[y-1][x] + graph[y+1][x] + graph[y][x-1])
    if y - 1 >= 0 and y + 1 < n and x + 1 < m:
        # ㅏ
        max_value = max(max_value, graph[y][x] + graph[y-1][x] + graph[y+1][x] + graph[y][x+1])
            
n, m = map(int, sys.stdin.readline().strip().split())

graph = []
for _ in range(n):
    arr = list(map(int, sys.stdin.readline().strip().split()))
    graph.append(arr)

max_num = max(map(max, graph))
    
max_value = 0
visited = [[0] * m for _ in range(n)]
for i in range(n):
    for j in range(m):
        visited[i][j] = 1
        Tetro(i, j, 1, graph[i][j])
        visited[i][j] = 0
        exception(i, j)

print(max_value)




5. 문제 링크
https://www.acmicpc.net/problem/14500

728x90
728x90

백준 파이썬 공부 2025.03.21
7662번 이중 우선순위 큐 (골드 4)

1. 문제
이중 우선순위 큐(dual priority queue)는 전형적인 우선순위 큐처럼 
데이터를 삽입, 삭제할 수 있는 자료 구조이다. 
전형적인 큐와의 차이점은 데이터를 삭제할 때 연산(operation) 명령에 따라 
우선순위가 가장 높은 데이터 또는 가장 낮은 데이터 중 하나를 삭제하는 점이다. 

이중 우선순위 큐를 위해선 두 가지 연산이 사용되는데, 
하나는 데이터를 삽입하는 연산이고 다른 하나는 데이터를 삭제하는 연산이다. 

데이터를 삭제하는 연산은 또 두 가지로 구분되는데 
하나는 우선순위가 가장 높은 것을 삭제하기 위한 것이고 
다른 하나는 우선순위가 가장 낮은 것을 삭제하기 위한 것이다.

정수만 저장하는 이중 우선순위 큐 Q가 있다고 가정하자. 
Q에 저장된 각 정수의 값 자체를 우선순위라고 간주하자.

Q에 적용될 일련의 연산이 주어질 때 이를 처리한 후 
최종적으로 Q에 저장된 데이터 중 최댓값과 최솟값을 출력하는 프로그램을 작성하라.

2. 입력
입력 데이터는 표준입력을 사용한다. 
입력은 T개의 테스트 데이터로 구성된다. 

입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 
각 테스트 데이터의 첫째 줄에는 
Q에 적용할 연산의 개수를 나타내는 정수 k (k ≤ 1,000,000)가 주어진다. 

이어지는 k 줄 각각엔 연산을 나타내는 문자(‘D’ 또는 ‘I’)와 정수 n이 주어진다. 

‘I n’은 정수 n을 Q에 삽입하는 연산을 의미한다. 
동일한 정수가 삽입될 수 있음을 참고하기 바란다. 

‘D 1’는 Q에서 최댓값을 삭제하는 연산을 의미하며, 
‘D -1’는 Q 에서 최솟값을 삭제하는 연산을 의미한다. 
최댓값(최솟값)을 삭제하는 연산에서 최댓값(최솟값)이 둘 이상인 경우, 
하나만 삭제됨을 유념하기 바란다.

만약 Q가 비어있는데 적용할 연산이 ‘D’라면 이 연산은 무시해도 좋다. 
Q에 저장될 모든 정수는 -2^31 이상 2^31 미만인 정수이다.

3. 출력
출력은 표준출력을 사용한다. 
각 테스트 데이터에 대해, 모든 연산을 처리한 후 
Q에 남아 있는 값 중 최댓값과 최솟값을 출력하라. 
두 값은 한 줄에 출력하되 하나의 공백으로 구분하라. 
만약 Q가 비어있다면 ‘EMPTY’를 출력하라.

4. 문제 풀이
일단 매번 추가하고 정렬하는 방식으로 시도한 후,
pop으로 맨 앞과 맨 뒤를 제거하는 방식으로 시도했다.
당연히 시간초과가 나온다.

>>>코드1. 정렬, 시간초과

import sys

T = int(sys.stdin.readline().strip())
for _ in range(T):
    Q = int(sys.stdin.readline().strip())
    queue = []
    for i in range(Q):
        arr = sys.stdin.readline().strip().split()
        if arr[0] ==  'I':
            queue.append(int(arr[1]))
            queue.sort()
        elif queue:
            if arr[1] == '1':
                queue.pop()
            else:
                queue.pop(0)
        
    if queue:
        if len(queue) == 1:
            num = queue.pop()
            print(num, num)
        else:
            print(queue.pop(), queue.pop(0))
    else:
        print("EMPTY")



그렇다면 제거하는 당시에 최대값과 최소값을 찾는건 어떨까?
역시나 시간초과이다.

>>>코드2. 최대값 최소값 찾기. 시간초과

import sys

T = int(sys.stdin.readline().strip())
for _ in range(T):
    Q = int(sys.stdin.readline().strip())
    queue = []
    for i in range(Q):
        arr = sys.stdin.readline().strip().split()
        if arr[0] ==  'I':
            queue.append(int(arr[1]))
        elif queue:
            if arr[1] == '1':
                queue.remove(max(queue))
            else:
                queue.remove(min(queue))
        
    if queue:
        if len(queue) == 1:
            num = queue.pop()
            print(num, num)
        else:
            print(queue.pop(), queue.pop(0))
    else:
        print("EMPTY")



>>>코드3. 그렇다면 최대값과 최소값을 저장해놓는건? 시간초과

import sys

T = int(sys.stdin.readline().strip())
for _ in range(T):
    Q = int(sys.stdin.readline().strip())
    queue = []
    Max, Min = -2**31, 2**31
    for i in range(Q):
        arr = sys.stdin.readline().strip().split()
        if arr[0] ==  'I':
            m = int(arr[1])
            queue.append(m)
            Max = max(Max, m)
            Min = min(Min, m)
        elif queue:
            if arr[1] == '1':
                queue.remove(Max)
                Max = max(queue)
            else:
                queue.remove(Min)
                Min = min(queue)
        
    if queue:
        if len(queue) == 1:
            num = queue.pop()
            print(num, num)
        else:
            print(queue.pop(), queue.pop(0))
    else:
        print("EMPTY")



저장하는 구조를 새로 생각을 해봐야겠다

최대 힙과 최소 힙에 동시에 저장을 한 후
딕셔너리로 해당 숫자와 숫자의 개수를 저장해놓는다.
삭제 시에는 해당 숫자의 개수가 0이 되면 딕셔너리에서 삭제하며,
삭제 하는 과정에서, 최대 힙과 최소 힙의 목록을 일치 시켜주는 작업을 시행한다.

큰 틀은 맞았으나, Key Error가 자꾸 발생한다.
원인은 딕셔너리 내부를 탐색하는 경우, 해당 key가 존재하지 않는 경우 오류가 난다.
따라서 해당 Key 값이 존재하지 않아도 오류가 발생하지 않는 탐색함수인
.get 함수를 사용하여 개수를 탐색한다.

get() 메서드는 다음과 같은 동작을 수행합니다:

- 만약 주어진 키(key)가 딕셔너리에 존재한다면, 해당 키에 대한 값을 반환합니다.
- 만약 주어진 키(key)가 딕셔너리에 존재하지 않는다면, 기본값(default value)을 반환합니다.
- 만약 기본값이 지정되지 않았다면, None을 반환합니다.

>>>코드 정답

import sys
import heapq

T = int(sys.stdin.readline().strip())
for _ in range(T):
    Q = int(sys.stdin.readline().strip())
    max_heap = []
    min_heap = []
    
    # 입력된 값과 개수를 저장할 딕셔너리
    cnt = {}
    for i in range(Q):
        arr = sys.stdin.readline().strip().split()
        
        # 값을 추가하는 경우
        if arr[0] ==  'I':
            n = int(arr[1])
            # 값과 개수을 딕셔너리에 저장
            if n in cnt:
                cnt[n] += 1
            else:
                cnt[n] = 1
            # 최대힙과 최소힙에 저장 (우선순위 존재)
            heapq.heappush(min_heap, n)
            heapq.heappush(max_heap, -n)
        
        # 값을 삭제하는 경우
        elif arr[0] == 'D' and cnt:
            # 최대값을 삭제하는 경우
            if arr[1] == '1':
                # 해당 값의 개수가 0 이하인 경우
                while max_heap:
                    # 최대 힙에서 삭제 (최소 힙과 목록 일치 시켜주는 작업)
                    max_val = -max_heap[0]
                    if cnt.get(max_val, 0) > 0:
                        break
                    heapq.heappop(max_heap)
                if max_heap:
                    # 해당 값의 개수 -1
                    max_val = -heapq.heappop(max_heap)
                    cnt[max_val] -= 1
                    if cnt[max_val] == 0:
                        del cnt[max_val]
            # 최소값을 삭제하는 경우
            elif arr[1] == '-1':
                # 해당 값의 개수가 0 이하인 경우
                while min_heap:
                    # 최소 힙에서 삭제 (최대 힙과 목록 일치 시켜주는 작업)
                    min_val = min_heap[0]
                    if cnt.get(min_val, 0) > 0:
                        break
                    heapq.heappop(min_heap)
                if min_heap:
                    # 해당 값의 개수 -1
                    min_val = heapq.heappop(min_heap)
                    cnt[min_val] -= 1
                    if cnt[min_val] == 0:
                        del cnt[min_val]

    if not cnt:
        print("EMPTY")
    else:
        while max_heap:
            max_val = -max_heap[0]
            if cnt.get(max_val, 0) > 0:
                break
            heapq.heappop(max_heap)
        while min_heap:
            min_val = min_heap[0]
            if cnt.get(min_val, 0) > 0:
                break
            heapq.heappop(min_heap)
        print(-max_heap[0], min_heap[0])



빡셌다.
구조는 맞는거 같은데 자꾸 오류가 발생해서 어지러웠다.

5. 문제 링크
https://www.acmicpc.net/problem/7662

728x90

+ Recent posts