import sys
from collections import defaultdict
def input():
    return sys.stdin.readline().rstrip()

max_coins = 50000
for _ in range(3):
    N = int(input())
    coins = defaultdict(int)
    dp = [0 for _ in range(max_coins+1)]
    dp[0] = 1
    total_sum = 0
    for _ in range(N):
        coin,cnts = map(int,input().split())
        for cur_coin in range(max_coins,coin-1,-1):
            if dp[cur_coin - coin]:
                for cnt in range(cnts):
                    next_coin = cur_coin + coin * cnt
                    if 0<=next_coin<=max_coins:
                        dp[next_coin] = 1
        total_sum += coin*cnts

    if total_sum%2 or not dp[total_sum//2]:
        print(0)
    else:
        print(1)

이 문제를 풀때 어려움을 많이 겪었다.

 

이 문제를 처음 푼 방식은 다음과 같다. dp는 동전을 만들수 있는 경우의 수이다.

 

먼저 dp[0]은 1로 초기화 해준다.

 

그리고 각 입력이 들어올때마다 dp를 max_coin에서 현재 들어온 동전인 coin 까지 반복문을 돌면서

 

cur_con - coin의 위치에 dp의 값이 존재하면, 만들 수 있는 경우의 수가 있으므로,

 

여기서 부터 다시 동전의 개수만큼 더해주면서 dp를 채워주면 된다.

 

이렇게 dp를 채워준 뒤에 전체 동전을 total_sum에 더해준다.

 

이렇게 한뒤에 만약 홀수 이거나 dp[total_sum//2]의 값이 존재하지 않으면 0을 출력한다.

 

 

import sys
from collections import defaultdict
def input():
    return sys.stdin.readline().rstrip()

def solution():
    N = int(input())
    coins = []
    total_coins = 0
    for _ in range(N):
        a,b = map(int,input().split())
        coins.append((a,b))
        total_coins += a*b
    if total_coins%2:
        return 0
    else:
        find_coin = total_coins//2
        dp = [0 for _ in range(find_coin+1)]
        dp[0] = 1
        coins.sort(key= lambda x : -x[1])
        acc_coins = 0
        for coin,cnts in coins:
            max_coin = coin*cnts
            for i in range(min(max(acc_coins,max_coin),find_coin),coin-1,-1):
                if dp[i-coin]:
                    for cnt in range(cnts):
                        next_coin = coin*cnt + i
                        if 0<=next_coin<=find_coin:
                            dp[next_coin] = 1
            if dp[find_coin]:
                return 1
            acc_coins += max_coin
        return 0
for _ in range(3):
    print(solution())

 

 

이 풀이는 좀 더 빠르대신 좀 더 복잡하다. 위에서는 고정된 최대값 50000에서부터 하나하나씩 찾는거라 하면,

 

이 풀이는 이 코인에서 가능한 최대값에서부터 하나씩 내려가는 것이다.

 

탐색이 가능한 최대 범위는 acc_coins 누적된 값 아니면 max_coin 중 더 큰 값에서부터 하나씩 내려가야한다.

 

우리는 dp[i - coin] coin 단 1개를 빼서 존재했을때부터 해당 동전이 가지는 개수를 갱신해주기 때문이다.

 

여기서 또 주의해야할 점은 위의 최대값이 find_coin을 넘어갈순 없다. 그러므로 둘중 min값 부터 시작해주면 된다.

'알고리즘 > 백준' 카테고리의 다른 글

[BOJ/백준] 1958 LCS 3  (0) 2021.09.28
[BOJ/백준] 2146 다리 만들기  (0) 2021.09.03
[BOJ/백준] 2143 두 배열의 합  (0) 2021.09.03
[BOJ/백준] 1823 수확  (0) 2021.09.03
[BOJ/백준] 1727 커플 만들기  (0) 2021.09.03

+ Recent posts