본문 바로가기

알고리즘 삽질장

(228)
[BOJ] 1309번 - 동물원 문제설명 https://www.acmicpc.net/problem/1309 1309번: 동물원 첫째 줄에 우리의 크기 N(1≤N≤100,000)이 주어진다. www.acmicpc.net 사고과정 타일 공사같은 DP 유형의 문제인가 생각했다. 우선은 N = 3일 떄까지 경우의 수를 연습장에 그려보았다. 타일 공사 문제에서 얻은 인사이트를 가지고 적용해보았다. 서로 사자들이 가로, 세로로 붙어있으면 안된다는 조건을 만족시켜야 한다! N이 1개씩 늘어남에 따라 마지막 줄 N by 2 칸의 입장에서 살펴보면 알 수 있다. 즉, 마지막 N번째 줄 2칸 중 왼쪽 칸만 채워져 있다면 N-1번째 줄에는 오른쪽 칸만 채워져 있거나 아무 칸에도 사자가 없어야 한다.(문제에서 아무 칸에 사자가 없어도 괜찮다고 했다) 반대로..
[BOJ] 1149번 - RGB거리 문제설명 https://www.acmicpc.net/problem/1149 1149번: RGB거리 첫째 줄에 집의 수 N(2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 각 집을 빨강, 초록, 파랑으로 칠하는 비용이 1번 집부터 한 줄에 하나씩 주어진다. 집을 칠하는 비용은 1,000보다 작거나 www.acmicpc.net 사고과정 문제에서 갑자기 거리는 선분으로 나타낼 수 있다는 말에 선분이 간선인가 싶어서 엥 그래프 알고리즘인가..? 했지만 문제를 더 읽어보니 선분은 중요치 않았다. 전형적인 DP 테이블을 2차원 리스트로 운영하는 문제였다. 단, 조건이 있었는데 서로 인접한 집들끼리는 무조건 다른 색깔을 칠해야 하는 것이었다. 따라서 이를 기반으로 점화식을 구현하면 된다. 처음에 D..
[BOJ] 15988번 - 1,2,3 더하기 3 문제설명 https://www.acmicpc.net/problem/15988 15988번: 1, 2, 3 더하기 3 각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 1,000,000,009로 나눈 나머지를 출력한다. www.acmicpc.net 사고과정 1,2,3 더하기 문제랑 동일한 점화식인 문제이다. 단, 주어지는 데이터 범위만 차이가 있다. 주어진 범위가 백만이라 입력 데이터를 받을 때 sys 라이브러리를 활용했다. 점화식은 다음과 같다. $dp[i] = dp[i-1] + dp[i-2] + dp[i-3]$ 참고로 n = 3일 때까지는 직접 경우의 수를 구해주어서 DP 테이블에 넣어주어야 한다. 그러므로 n이 1,2,3일 때는 개별로 처리하도록 해준다. 만약 안해주면 Inde..
[BOJ] 2225번 - 합분해 문제설명 https://www.acmicpc.net/problem/2225 2225번: 합분해 첫째 줄에 답을 1,000,000,000으로 나눈 나머지를 출력한다. www.acmicpc.net 사고과정 0~N까지 수 중에서 K개를 아무거나 뽑아서 합이 N이 되는 경우의 수를 모두 구하는 것이었다. 2차원 리스트 DP 테이블을 운영해야 하는 느낌이 들어서 시도해보았더니 맞는 풀이였다! DP 테이블의 행($i$)는 N을, 열($j$)는 K로 하고 원소값을 몇 가지 예시로 연습장에 구현해보면 특정한 규칙이 발생한다는 것을 포착할 수 있었다. 이 때, DP 테이블에서 N=1일 때는 K가 어떤 값이냐에 따라 K개가 되었다. 반대로 K=1일 때는 N이 무엇이던 간에 모두 1개임을 알 수 있다. 따라서 초기 DP 테..
[BOJ] 1699번 - 제곱수의 합 문제설명 https://www.acmicpc.net/problem/1699 1699번: 제곱수의 합 어떤 자연수 N은 그보다 작거나 같은 제곱수들의 합으로 나타낼 수 있다. 예를 들어 11=32+12+12(3개 항)이다. 이런 표현방법은 여러 가지가 될 수 있는데, 11의 경우 11=22+22+12+12+12(5개 항)도 가능하다 www.acmicpc.net 사고과정 점화식을 발견하기가 어려웠다.. 제곱수를 어떻게 해야할지 몰랐다.. 풀이의 핵심적인 아이디어만 보고 소스코드는 직접 작성해보았다. 다행히 이건 통과했다. 문제풀이의 핵심 아이디어는 DP 테이블에는 입력되는 N을 제곱수 합으로 만들 수 있는 가장 최소항 개수를 넣어준다. 그리고 숫자를 $i$라고 할때, $j$는 $i$보다 작거나 같은 제곱수..
[BOJ] 1912번 - 연속합 문제설명 https://www.acmicpc.net/problem/1912 1912번: 연속합 첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다. www.acmicpc.net 사고과정 연속된 수열을 '몇 개'를 선택했을 때 가장 큰 합을 구하는 것이었다. 그래서 DP 테이블을 어떻게 작성해야 할까 매우 고민했다. 생각보다 너무 복잡하게 생각한 듯 했다..(풀이를 보니..) 주어진 데이터 범위가 최대 10만이였기 때문에 이중 loop만 돌아도 시간초과 에러가 발생할 게 뻔했다. 그래서 한 번의 loop로 해결해야 하는데.. 잘 떠오르지 않았다. 풀이를 보니 DP 테이블을..
[BOJ] 14002번 - 가장 증가하는 부분 수열 4 문제설명 https://www.acmicpc.net/problem/14002 14002번: 가장 긴 증가하는 부분 수열 4 수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이 www.acmicpc.net 사고과정 아무거나 수열 출력하는 부분에서 매우 고생했다.. 오히려 문제의 난이도가 여기에서 올라가는 것 같다.. 반례에 자꾸 걸려서 구글링을 했는데 구글링한 것 중에서도 간결한 코드를 찾기가 쉽지 않았다. 그러던 중 하나의 훌륭한 블로그 글을 발견하고! 해당 풀이를 참조했다!(감사합니다 :) 풀이(스스로 못..
[BOJ] 11053번 - 가장 긴 증가하는 부분 수열 문제설명 https://www.acmicpc.net/problem/11053 11053번: 가장 긴 증가하는 부분 수열 수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이 www.acmicpc.net 사고과정 이전에 이코테 문제에서 풀어본 병사 배치하기 문제를 통해서 LIS(가장 긴 증가하는 부분 수열) 알고리즘에 대해 배웠었다. git 팀 노트에 적어놓긴 했었지만 다시 회상할 겸 소스코드를 보지 않고 직접 머릿속으로 구현하려 했다. LIS 알고리즘 개념은 여기를 참고하자. 풀이 a = int(input()..
[BOJ] 2193번 - 이친수 문제설명 https://www.acmicpc.net/problem/2193 2193번: 이친수 0과 1로만 이루어진 수를 이진수라 한다. 이러한 이진수 중 특별한 성질을 갖는 것들이 있는데, 이들을 이친수(pinary number)라 한다. 이친수는 다음의 성질을 만족한다. 이친수는 0으로 시작하지 않 www.acmicpc.net 사고과정 경우의 수를 n = 7까지 나열해보고 패턴을 못찾는 듯 했으나..! 간신히 찾았다! 매우 간단한 점화식이었다. $dp[i] = dp[i-1] + dp[i-2]$ 처음에 인덱스 에러가 발생했는데, n = 1일 때의 조건을 처리해주어야 한다. DP에서는 입력이 1일 때 처리를 해주는 조건을 자주 붙이는 듯 하다. 1,2,3 더하기 문제랑 동일한 점화식이었다. 아쉽다고 한다..
[BOJ] 10844번 - 쉬운 계단 수 문제설명 https://www.acmicpc.net/problem/10844 10844번: 쉬운 계단 수 첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다. www.acmicpc.net 사고과정 1,2,3 더하기 5 유형과 비슷한 유형이였다. 이것도 2차원 리스트를 DP 테이블로 하는 것이었다. 이 때, DP 테이블에서 행($i$)는 글자 길이인 N을 의미하고 열($j$)는 맨 뒷자리에 나올 수 있는 숫자인 0부터 9까지이다. DP 테이블을 2차원으로 그리고 N = 3일 때까지 경우의 수를 세서 해보면 규칙을 파악할 수 있다. 바로 왼쪽 대각선 위와 오른쪽 대각선 위의 합이 DP[i][j] 값이라는 것! 이 때 j = 0 일 때는 왼쪽 대각선 위가 없으므로 오른쪽 대각선 위만 더하고..
[BOJ] 15990번 - 1, 2, 3 더하기 5 문제설명 https://www.acmicpc.net/problem/15990 15990번: 1, 2, 3 더하기 5 각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 1,000,000,009로 나눈 나머지를 출력한다. www.acmicpc.net 사고과정 저번 1,2,3 더하기 문제와 난이도가 매우 달랐던 것 같다.. DP 테이블을 1차원으로 정의하고 어떻게든 규칙을 찾아보려 했지만 실패했다. 핵심 풀이는 2차원으로 DP 테이블을 운영하는 것이었고 또 하나는 다이나믹 프로그래밍의 핵심인 "뒤의 입장에서 생각" 하기 였다. 어떤 뒤의 입장이냐.. 바로 1, 2, 3 합으로만 이루어진 것을 찾는 것이므로 특정한 수 n을 1, 2, 3의 합으로 만들 때, 그 연산에 사용된 마지막 피연산..
[BOJ] 16194번 - 카드 구매하기 2 문제설명 https://www.acmicpc.net/problem/16194 16194번: 카드 구매하기 2 첫째 줄에 민규가 구매하려고 하는 카드의 개수 N이 주어진다. (1 ≤ N ≤ 1,000) 둘째 줄에는 Pi가 P1부터 PN까지 순서대로 주어진다. (1 ≤ Pi ≤ 10,000) www.acmicpc.net 사고과정 카드 구매하기 문제랑 똑같은 문제이다. 단, 이번엔 최솟값인데, 점화식에서 max를 min으로만 바꾸어주면 된다. 카드 구매하기 문제에 대한 풀이는 여기를 참고하자. 풀이 n = int(input()) card = [0] + list(map(int, input().split())) dp = [0] * (n+1) dp[1] = card[1] dp[2] = min(card[2], car..
[BOJ] 11052번 - 카드 구매하기 문제설명 https://www.acmicpc.net/problem/11052 11052번: 카드 구매하기 첫째 줄에 민규가 구매하려고 하는 카드의 개수 N이 주어진다. (1 ≤ N ≤ 1,000) 둘째 줄에는 Pi가 P1부터 PN까지 순서대로 주어진다. (1 ≤ Pi ≤ 10,000) www.acmicpc.net 사고과정 경우의 수를 어느정도 나열해서 규칙을 발견하려 했는데 파악하지 못했다..뭔가 숨은 그림찾기 하는 느낌이다.. 바로 1번의 loop로 해결할 수 있지 않을까 했는데, n이 증가할 수록 비교하는 경우의 수가 많아짐에 따라 2중 루프를 사용했다. 예를 하나 들어보자. dp[1] 은 1번 카드 1개를 쓰는 방법만 있다. dp[2] 는 1번 카드를 2번 or 2번 카드를 1번 쓰는 방법만 있다...
[BOJ] 9095번 - 1, 2, 3 더하기 문제설명 https://www.acmicpc.net/problem/9095 9095번: 1, 2, 3 더하기 각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다. www.acmicpc.net 사고과정 경우의 수를 n = 5까지 나열해보고 '뒤의 입장'에서 생각해보려고 하는데 규칙을 찾지 못했다.. 풀이를 보니 매우 간단한 규칙이였다.. n이 4이상부터는 n-1, n-2, n-3일 때의 개수를 합해주면 된다.. 이런.. 매우 간단한 걸 캐치 못하다니..😢 점화식으로 나타내면 다음과 같다. $dp[i] = dp[i-1] + dp[i-2] + dp[i-3]$ 풀이(스스로 못 푼 풀이) for tc in range(int(input())): n = int(input()) dp =..
[BOJ] 11726번 - 2Xn 타일링 문제설명 https://www.acmicpc.net/problem/11726 11726번: 2×n 타일링 2×n 크기의 직사각형을 1×2, 2×1 타일로 채우는 방법의 수를 구하는 프로그램을 작성하시오. 아래 그림은 2×5 크기의 직사각형을 채운 한 가지 방법의 예이다. www.acmicpc.net 사고과정 예전에 풀어본 이코테의 바닥 공사랑 거의 유사한 유형이다. 단, 주어진 타일 종류가 다르다. 먼저 n = 2,3 될때까지 직접 그려보면서 다이나믹 프로그래밍의 "뒤의 입장에서 생각"하는 마인드로 접근해서 점화식을 잘 세울 수 있었다. 단, 몇 번 초반에 자꾸 에러를 받았는데, n = 1일 때 반례를 생각하지 못했다. n = 1 이게 되면 dp 테이블에서 2번 인덱스까지 정의했는데, 초기 array의 ..
[BOJ] 17103번 - 골드바흐 파티션 문제설명 https://www.acmicpc.net/problem/17103 17103번: 골드바흐 파티션 첫째 줄에 테스트 케이스의 개수 T (1 ≤ T ≤ 100)가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 N은 짝수이고, 2 < N ≤ 1,000,000을 만족한다. www.acmicpc.net 사고과정 골드바흐의 추측 문제와 비슷하게 풀이하면 된다. 단, a, b 쌍의 개수를 구하여야 하는데, 순서가 다른 a, b도 같은 것으로 여기므로 일종의 조합을 구해야 하는 문제이다. 어차피 순서가 다른 것도 같은 것으로 취급하기 때문에 n = a + b 경우를 돌 때, a가 n // 2 일 때까지만 돌면 된다! 참고로 처음에 array[2] = False로 해서 에라토스테네스 체에서 2의..
[BOJ] 1373번 - 2진수 8진수 문제설명 https://www.acmicpc.net/problem/1373 1373번: 2진수 8진수 첫째 줄에 2진수가 주어진다. 주어지는 수의 길이는 1,000,000을 넘지 않는다. www.acmicpc.net 사고과정 진수 변환방법은 아래와 같으며 10진수가 아닌 다른 진수에서 다른 진수로 바꾸려면 중간에 10진수 변환하는 과정을 꼭 거쳐야 한다. ex) 2진수 -> 8진수 = 2진수 -> 10진수 -> 8진수 진수에 따라 앞에 2글자 문자열이 붙는다 2진수: 0b -> 그래서 10진수에서 2진수로 바꾸려면 bin(10진수) 8진수: 0o -> 그래서 10진수에서 8진수로 바꾸려면 oct(10진수) 16진수: 0x -> 그래서 10진수에서 16진수로 바꾸려면 hex(10진수) 반대로 다른 진수에서..
[BOJ] 17087번 - 숨바꼭질 6 문제설명 https://www.acmicpc.net/problem/17087 17087번: 숨바꼭질 6 수빈이는 동생 N명과 숨바꼭질을 하고 있다. 수빈이는 현재 점 S에 있고, 동생은 A1, A2, ..., AN에 있다. 수빈이는 걸어서 이동을 할 수 있다. 수빈이의 위치가 X일때 걷는다면 1초 후에 X+D나 X-D로 이 www.acmicpc.net 사고과정 처음에 수빈이 위치인 S와 주어진 동생의 위치 간의 거리값을 구하고 이 거리값들 간의 최대공약수를 구하는 것 같다고 생각했었다. 그런데 갑자기 왜인지 모르게 그리디 방식으로 구현할 수 있을 것 같아 구현했는데 틀렸다는 판정이 나왔다.. 최대공약수를 활용한 풀이는 처음에 수빈이 위치와 주어진 동생의 위치 첫 번째 간의 최대공약수를 초기 answer로..
[BOJ] 9613번 - GCD 합 문제설명 https://www.acmicpc.net/problem/9613 9613번: GCD 합 첫째 줄에 테스트 케이스의 개수 t (1 ≤ t ≤ 100)이 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있다. 각 테스트 케이스는 수의 개수 n (1 < n ≤ 100)가 주어지고, 다음에는 n개의 수가 주어진 www.acmicpc.net 사고과정 처음에 입력으로 주어지는 문제를 대충 읽어서 좀 헤맸다.. 테스트 케이스 숫자 이후로 입력주어질 때 가장 맨 처음에 나오는 숫자는 다음에 나올 숫자의 개수를 의미했다.. 문제 좀 제대로 읽자 제에발! math 라이브러리와 모든 쌍을 구하기 위해 itertools의 조합 라이브러리를 활용 풀이 import math from itertools import c..
[BOJ] 2004번 - 조합 0의 개수 문제설명 https://www.acmicpc.net/problem/2004 2004번: 조합 0의 개수 첫째 줄에 정수 $n$, $m$ ($0 \le m \le n \le 2,000,000,000$, $n \ne 0$)이 들어온다. www.acmicpc.net 사고과정 주어진 데이터 범위가 20억이기 때문에 매우 큰 수다. 따라서 조합을 다 계산하는 것이 아닌 0의 개수만을 찾아야 함. 0개수는 2와 5의 개수로 알아낼 수 있다. 자세한 설명은 여기를 참고하자. 풀이(스스로 못 푼 풀이) import sys input = sys.stdin.readline n, k = map(int, input().split()) # (n, k) def count(n, num): cnt = 0 divnum = num wh..