def checkWin(play):
    play_num = players[play]

    for x in range(3):
        if arr[x][0] == arr[x][1] == arr[x][2] == play_num:
            return 2
    
    for y in range(3):
        if arr[0][y] == arr[1][y] == arr[2][y] == play_num:
            return 2

    if arr[0][0] == arr[1][1] == arr[2][2] == play_num:
        return 2

    if arr[0][2] == arr[1][1] == arr[2][0] == play_num:
        return 2

    return 0 


def dfs(rc,play):
    global result
    if checkWin((play+1)%2)>1:
        return -1
    if rc <remain_cnt:
        check_result = 10
        for idx in range(remain_cnt):
            if not visited[idx]:
                visited[idx] = True
                x,y = remain_list[idx]
                arr[x][y] = players[play]
                check_result = min(check_result,dfs(rc+1,(play+1)%2))
                visited[idx] = False
                arr[x][y] = 0
        if check_result == 10 or check_result == 0:
            return 0
        else:
            return -check_result
    return 0 
arr = []

# 1 = X
# 2 = O
# 착수하는 사람 부터
cnt_1 = 0
cnt_2 = 0
remain_cnt = 0
remain_list = []
players = [1,2]
for x in range(3):
    temp = list(map(int,input().split()))

    for y in range(3):
        if temp[y] == 1:
            cnt_1 += 1
        elif temp[y] == 2:
            cnt_2 += 1
        else:
            remain_cnt += 1
            remain_list.append((x,y))

    arr.append(temp)
visited = [False for _ in range(remain_cnt)]

start = 0
if cnt_1 > cnt_2:
    start = 1




result = dfs(0,start)
answer = ['D','W','L']
print(answer[result])

 이 문제는 어려웠던 문제였다.  이 문제는 각각 최선의 수로 둔다는 것은 해당 수를 두고 다음턴에, 지지 않기를 바라는 상황이다.

 

그래서 상대턴이 시작할때, 이전턴에 뒀던 플레이어의 승리여부를 체크하고 체크를 한뒤에는 음수를 보내준다.

 

왜냐하면 서로 승패는 반대로 되기 때문이다. 그리고 승부가 나지 않았을 시에는 0을 반환하도록 한다.

 

 

 

def check():
    for x in range(3):
        prev_num = arr[x][0]
        if not prev_num:continue
        for y in range(1,3):
            if prev_num != arr[x][y]:
                break
        else:
            return prev_num
    
    for y in range(3):
        prev_num = arr[0][y]
        if not prev_num: continue
        for x in range(1,3):
            if prev_num != arr[x][y]:
                break
        else:
            return prev_num

    prev_num = arr[0][0]
    if prev_num:
        for k in range(1,3):
            if prev_num != arr[k][k]:
                break
        else:
            return prev_num
    
    prev_num = arr[0][2]
    if prev_num:
        for k in range(1,3):
            if prev_num != arr[k][2-k]:
                break
        else:
            return prev_num

    return 0


def dfs(rc,player):
    check_num = check()
    if check_num != 0:
        return check_num

    if rc == 0: return -1
    response = []
    for x in range(3):
        for y in range(3):
            if arr[x][y]:continue
            arr[x][y] = player
            response.append(dfs(rc-1,3-player))
            arr[x][y] = 0
    if player in response:return player
    if -1 not in response: return (3-player)
    return -1

arr = [list(map(int,input().split())) for _ in range(3)]
cnt_1 = 0
cnt_2 = 0
player = 1
r_cnt = 0
for x in range(3):
    for y in range(3):
        if arr[x][y] == 1:
            cnt_1 += 1
        elif arr[x][y] == 2:
            cnt_2 += 1
        else:
            r_cnt += 1


if cnt_1 > cnt_2:
    player = 2


result = dfs(r_cnt,player)

if result == -1:
    print('D')
elif result == player:
    print('W')
else:
    print('L')

이 풀이가 좀 더 직관적일 수 있다.

 

모든 결과들을 저장한뒤에 해당 결과 내에서, 해당 플레이어의 번호가 있으면 승리한 것이므로, 해당 플레이어 번호를 보내주고,

 

무승부인 -1이 없으면 상대방이 이긴거기 때문에 상대방의 플레이어 번호를 return 해준다.

 

그리고 둘다 아닌경우에는 무승부이므로 -1을 반환해준다.

 

이 문제는 최선의 수가 무엇인지, 어떻게 승패를 판단하는지 어려웠던 문제였다.

from itertools import combinations

def dfs(cu_val,cnt,pick_list):
    global result
    if cnt == 0:
        result = max(result,cu_val*sum(pick_list))
        return cu_val * sum(pick_list)
    else:

        idx_list = range(len(pick_list))
        for pick_cnt in range(1,len(pick_list)-cnt+1):
            for comb in combinations(idx_list,pick_cnt):
                copy_pick_list = pick_list[:]
                comb = list(reversed(comb))
                temp_sum = 0
                for idx in comb:
                    temp_sum += copy_pick_list.pop(idx)                
                dfs(cu_val*temp_sum,cnt-1,copy_pick_list)







N = int(input())

arr = list(map(int,input().split()))

p_cnt,a_cnt = map(int,input().split())


result = 0
dfs(1,a_cnt,arr)
print(result)

 

생각 난대로 풀었더니, 운좋게 풀린 문제였다.

 

이 문제에서 주의해야할 점은 숫자는 순서에 상관없이 배치를 해도 되고, 더하기와 곱셈의 우선순위가 같다.

 

이 2가지를 주의해야한다.

 

이 문제를 풀때 최대값을 구할때 중요하다고 생각한 것이 곱셈이라고 생각했다.

 

 

곱셈을 기준으로 구역을 나누고, 그 사이에 숫자를 집어넣으면 된다고 생각했다.

 

즉 곱셈의 기호가 3개가 주어진다면

 

 

이렇게 4구역으로 나눌수 있다고 생각했다.

 

즉 주어진 숫자들을 4팀으로 나누면 된다.

 

그리고 각 팀은 최소1명이상 이어야만 한다라는 조건을 만족해야한다.

 

그런 방식으로 숫자를 나눠주고, 나뉜 숫자들을 합을 계속 곱해주면서 idx가 마지막까지 올때까지 해주었다.

 

위의 dfs라는 함수가 그것을 의미한다.

 

현재 위치에서 최대로 뽑을 수 있는 숫자는 남은숫자 - 곱셈 기호가 남은개수 만큼 뽑을 수 있다.

 

그렇게 1개부터 (남은숫자 - 곱셈기호가 남은 개수)까지 반복문을 돌리면서

 

숫자들을 뽑아서 재귀를 해주었다.

 

 

# edenooo님 코드 복기
from itertools import permutations
def dfs(idx,cnt,position,num_list):
    global result
    if (cnt+N-1-idx)<Q:
        return
    if idx == N-1:
        position.append(idx)
        mul_val = 1
        sum_val = 0
        cu_idx = 0
        for mul_idx in position:
            while (cu_idx<=mul_idx):
                sum_val += num_list[cu_idx]
                cu_idx += 1
            mul_val *= sum_val
            sum_val = 0
        result = max(result,mul_val)
        position.pop()
        return
    dfs(idx+1,cnt,position,num_list)
    position.append(idx)
    if cnt+1<=Q:
        dfs(idx+1,cnt+1,position,num_list)
    position.pop()
N = int(input())
arr = list(map(int,input().split()))
result = 0
arr.sort()

P,Q = map(int,input().split())
for perm in permutations(arr):
    dfs(0,0,[],perm)
print(result)

이 풀이는 edenooo님의 풀이이다. 기본적인 아이디어는 비슷하다고 볼 수 있다.

 

여기서는 모든 숫자들이 나올 수 있는 배치들을 만들어두고, 곱셈의 위치를 변경시켜서 해주는 방식으로 해주었다.

from collections import deque
import sys

R,C,T = map(int,input().split())


arr = []
start = []
for x in range(R):
    temp = list(input())

    for y in range(C):
        if temp[y] == 'G':
            start = (x,y)

    arr.append(temp)


stack = []

stack.append((*start,0,set()))
time = 0
result = 0
dx = [-1,1,0,0]
dy = [0,0,1,-1]
while time<T:
    new_stack = []
    for x,y,eat,visited in stack:
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0 <= nx<R and 0<=ny<C:
                if arr[nx][ny] == 'S' and (nx,ny) not in visited:
                    new_visited = set()
                    new_visited.add((nx,ny))
                    new_visited = new_visited | visited
                    new_stack.append((nx,ny,eat+1,new_visited))
                    result = max(eat+1,result)
                elif arr[nx][ny] != '#':
                    new_stack.append((nx,ny,eat,visited))
    stack = [row[:] for row in new_stack]
    time += 1

print(result)
    

 

 

대회때 풀었던 풀이는 다음과 같다 BFS를 해주면서, 모든 이동경로를 누적해줬다.

 

그리고 visited에 없는 경우에만 고구마를 먹도록 해줬다.

 

import sys
input = sys.stdin.readline
sys.setrecursionlimit(100000)
def dfs(node,time,eat):
    global T,result,R,C
    if time == T:
        result = max(result,eat)
        return
    else:
        result = max(result,eat)
        for i in range(4):
            nx = node[0] + dx[i]
            ny = node[1] + dy[i]
            if 0<=nx<R and 0<=ny<C and not vistied[nx][ny]:
                vistied[nx][ny] = True
                if arr[nx][ny] == 'S':
                    dfs((nx,ny),time+1,eat+1)
                else:
                    dfs((nx,ny),time+1,eat)
                vistied[nx][ny] = False
            elif 0<=nx<R and 0<=ny<C and vistied[nx][ny] and arr[nx][ny] !='#':
                dfs((nx,ny),time+1,eat)

R,C,T = map(int,input().split())
result = 0
vistied = [[False for _ in range(C)] for _ in range(R)]


arr = []
start = []
for x in range(R):
    temp = list(input())
    for y in range(C):
        if temp[y] == '#':
            vistied[x][y] = True
        elif temp[y] == 'G':
            start = (x,y)
    arr.append(temp)


dx = [-1,1,0,0]
dy = [0,0,-1,1]

dfs(start,0,0)
print(result)

대회가 끝나고 난뒤의 풀이이다.

 

dfs를 해주는데 바문을 최초로 한 경우의 S일때에만 고구마를 먹도록 했다.

 

그리고, 방문을 했지만, 벽만 아니라면, 지나갈수 있도록 만들어줬다.

import sys

R,C = map(int,input().split())

GR,GC,PR,PC = map(int,input().split())


arr = []
P_total = PR*PC
for _ in range(R):
    temp = list(input())
    P_total-=temp.count('P')
    arr.append(temp)

if P_total:
    print(1)
else:
    print(0)

대회 때에는 너무 어렵게 생각해서 dfs,bfs를 이용해서 전체 베개의 개수를 구하는 방식으로 풀었는데,

 

대회 끝나고 간단한 풀이는 count로 P의 개수를 세주고, 그게 전체 배게의 넓이하고 같으면

 

가희는 위에서 자는게 아니고, 적으면, 가희가 위에서 자는것이다.

from itertools import permutations

import sys
input = sys.stdin.readline
def rotate(command,moving_arr):
    global arr
    cnt = 1
    while cnt<=command[2]:
        start_row,start_col = command[0]-cnt, command[1]-cnt
        end_row,end_col = command[0] + cnt,command[1] + cnt
        for row in range(start_row,end_row+1):
            if row == start_row or row == end_row:
                if row == start_row:
                    for col in range(start_col,end_col+1):
                        if col == end_col:
                            moving_arr[row+1][col] = prev_arr[row][col]
                        else:
                            moving_arr[row][col+1] = prev_arr[row][col]
                else:
                    for col in range(end_col,start_col-1,-1):
                        if col == start_col:
                            moving_arr[row-1][col] = prev_arr[row][col]
                        else:
                            moving_arr[row][col-1] = prev_arr[row][col]
            else:
                moving_arr[row-1][start_col] = prev_arr[row][start_col]
                moving_arr[row+1][end_col] = prev_arr[row][end_col]
        cnt += 1


N,M,K = map(int,input().split())
arr = [list(map(int,input().split())) for _ in range(N)]
command_list = []
for _ in range(K):
    x,y,r = map(int,input().split())
    command_list.append((x-1,y-1,r))
result = float('inf')

for commands in permutations(command_list):
    move_arr = [row[:] for row in arr]
    prev_arr = [row[:] for row in arr]
    for command in commands:
        rotate(command,move_arr)
        prev_arr = [row[:] for row in move_arr]
    arr_min = min(list(map(sum,move_arr)))
    result = min(arr_min,result)
print(result)

 

 

 

from itertools import permutations

import sys
input = sys.stdin.readline


def rotate(command,move_arr):
    x,y,s = command
    for i in range(1,s+1):
        subtract_data = move_arr[x-i][y-i] # 좌측 최상단 꼭지점을 빼놓기
        for r in range(x-i,x+i): # 좌측 세로를 아래에서 위로 올리는 과정
            move_arr[r][y-i] = move_arr[r+1][y-i]
        for c in range(y-i,y+i):
            move_arr[x+i][c] = move_arr[x+i][c+1]
        for r in range(x+i,x-i,-1):
            move_arr[r][y+i] = move_arr[r-1][y+i]
        for c in range(y+i,y-i+1,-1):
            move_arr[x-i][c] = move_arr[x-i][c-1]
        move_arr[x-i][y-i+1] = subtract_data
        





N,M,K = map(int,input().split())
arr = [list(map(int,input().split())) for _ in range(N)]
command_list = []
for _ in range(K):
    x,y,r = map(int,input().split())
    command_list.append((x-1,y-1,r))
result = float('inf')


for commands in permutations(command_list):

    move_arr = [row[:] for row in arr]
    for command in commands:
        rotate(command,move_arr)
    arr_min = min(list(map(sum,move_arr)))
    result = min(arr_min,result)
print(result)

'알고리즘 > 백준_복기_미완료' 카테고리의 다른 글

[BOJ/백준] 17837 새로운 게임 2  (0) 2021.05.06
[BOJ/백준] 17779 게리맨더링 2  (0) 2021.05.06
[BOJ/백준] 17404 RGB 거리 2  (0) 2021.05.06
[BOJ/백준] 17298 오큰수  (0) 2021.05.06
[BOJ/백준] 17281 ⚾  (0) 2021.05.06
def dfs(x,y,cnt):
    global result
    if cnt > result:
        return
    if x >= 10:
        result = min(result,cnt)
        return
    if y >= 10:
        dfs(x+1,0,cnt)
        return
    if arr[x][y] == 1:
        for paper_size in range(5,0,-1):
            if paper[paper_size]:
                if x + paper_size <= 10 and y + paper_size <= 10:
                    flag = False
                    for dx in range(paper_size):
                        for dy in range(paper_size):
                            if not arr[x+dx][y+dy]:
                                flag = True
                                break
                        if flag:
                            break
                    if not flag:
                        for dx in range(paper_size):
                            for dy in range(paper_size):
                                arr[x+dx][y+dy] = 0
                        paper[paper_size] -= 1
                        dfs(x,y+paper_size-1,cnt+1)
                        paper[paper_size] += 1
                        for dx in range(paper_size):
                            for dy in range(paper_size):
                                arr[x+dx][y+dy] = 1
    else:
        dfs(x,y+1,cnt)

        


arr = [list(map(int,input().split())) for _ in range(10)]
paper = [0]+[5]*5
result = float('inf')
dfs(0,0,0)
print(result if result != float('inf') else -1)

 

 

 

def check(x,y,size):
    if x + size > 10 or y + size >10:
        return False
    for dx in range(size):
        for dy in range(size):
            if not arr[x+dx][y+dy]:
                return False
    return True


def set_position(x,y,size,val):
    for dx in range(size):
        for dy in range(size):
            arr[x+dx][y+dy] = val
def dfs(x,y,cnt):
    global result
    if cnt >= result:
        return
    finish = True
    while x < 10:
        while y < 10:
            if arr[x][y] == 1:
                finish = False
                for paper_size in range(5,0,-1):
                    if paper[paper_size] and check(x,y,paper_size):
                        set_position(x,y,paper_size,0)
                        paper[paper_size] -= 1
                        dfs(x,y+paper_size-1,cnt+1)
                        paper[paper_size] += 1
                        set_position(x,y,paper_size,1)
                return
            y += 1
        x += 1
        y = 0
    if finish:
        result = min(result,cnt)
        


arr = [list(map(int,input().split())) for _ in range(10)]
paper = [0]+[5]*5
result = float('inf')
dfs(0,0,0)
print(result if result != float('inf') else -1)
def check(cnt,total,di):
    global result
    if cnt == arr[0]:
        temp = 1
        for k in di:
            temp *= arr[dire.index(k)+1]/100
        result += temp
        return
    else:
        cu_x,cu_y = total[-1]
        for i in range(4):
            nx = cu_x + dx[i]
            ny = cu_y + dy[i]
            if (nx,ny) not in total:
                check(cnt+1,total+[(nx,ny)],di+[dire[i]])
    


# 동 서 남 북
dx = [0,0,1,-1]
dy = [1,-1,0,0]
dire = ['E','W','S','N']
arr = list(map(int,input().split()))
result = 0
check(0,[(0,0)],[])
print(ccnt)

 

 

def dfs(x,y,persent,cnt):
    global revers_persen,N,total
    if arr[x][y] == 1:
        revers_persen += persent
        return
    if cnt == N:
        return
    arr[x][y] = 1
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if persentlist[i]:
            dfs(nx,ny,persent*persentlist[i],cnt+1)
    arr[x][y] = 0



N,e,w,s,n = map(int,input().split())

e,w,s,n = e/100,w/100,s/100,n/100
dx = [0,0,1,-1]
dy = [1,-1,0,0]
persentlist = [e,w,s,n]
arr = [[0]*29 for _ in range(29)]

revers_persen = 0
dfs(14,14,1,0)
print(f'{1-revers_persen:.10f}')
from itertools import combinations

N,K = map(int,input().split())
ord_dict = {}
if K <5:
    print(0)
    exit()
elif K == 26:
    print(N)
    exit()
else:
    # 2**승으로 만들어 주기 위한 곳
    for k in range(26):
        ord_dict[chr(k+97)] = k

    K = K - 5
    comb_bits = 0
    # 무조건 있는 애들을 기본적으로 comb_bits로 만들어준다.
    for k in ['a','n','t','i','c']:
        comb_bits = comb_bits + 2**ord_dict[k]
    word_list = []


    for _ in range(N):
        # 앞뒤 고정 부분은 필요없으니 자른다.
        temp = set(list(input())[4:-4])
        word_list.append(temp)
    # 고정적으로 잇는 부분 제외하고 나머지를 뽑는다.
    combi_word = set(ord_dict.keys()) - set(['a','n','t','i','c'])
    result = 0
    for pick_words in combinations(combi_word,K):
        check_bits = comb_bits
        for pick_word in pick_words:
            # OR 연산을 해줘서 BIT 형식으로 만들어준다.
            check_bits = check_bits | 1<< ord_dict[pick_word]

        word_cnt = 0
        for word in word_list:
            for wo in word:
                # 만약에 AND 연산을 했는데 False가 나오면 그만둔다.
                if not (check_bits & 1<<ord_dict[wo]):
                    break
            else:
                word_cnt += 1
        result = max(word_cnt,result)
                
    print(result)

 

 

어렵지 않은 문제인데 python을 이용해서 풀려면 참 난감해진 문제였다. 조합을 잘 짜면, 시간을 넘지않을수도 있지만, 

 

시간초과에 걸리는 경우가 많았다.

 

그래서 조합을 구하는 방식을 비트마스킹을 통해 만들었따. 2**(k)승의 형태로 만들어주고, and 연산을 해서 우리가 만든 조합에 포함되어있는지 아닌지 확인하는 방식이다.

 

from itertools import combinations

N,K = map(int,input().split())
ord_dict = {}

for k in range(26):
    ord_dict[chr(k+97)] = k

K = K - 5
if K <0:
    print(0)
    exit(0)
else:
    origin_word = set(['a','n','t','i','c'])
    word_bit_list = list()
    combination_word = set()
    answer = 0
    for _ in range(N):
        temp = set(list(input())[4:-4]) - origin_word
        if len(temp) == 0:
            answer += 1
        elif len(temp) <=K:
            word_bit = 0
            for w in temp:
                word_bit = word_bit + 2**ord_dict[w]
            word_bit_list.append(word_bit)
            combination_word |= temp

    word_lens = len(combination_word)
    if K > word_lens:
        K = word_lens
    chk_cnt = 0
    for pick_words in combinations(combination_word,K):
        cnt = 0
        temp = 0
        for pick_word in pick_words:
            temp = temp + 2**ord_dict[pick_word]
        for word_bit in word_bit_list:
            if word_bit & temp == word_bit:
                cnt += 1

        chk_cnt = max(chk_cnt,cnt)

    print(answer + chk_cnt)

위의 방식보다 훨씬 빠른 방식이다. 이 방식은 기본적인 컨셉은 비슷하다.

 

하지만 2가지가 다르다.

 

첫번째는 전체 알파벳 26개중에서 K개를 뽑던거에서 고정적으로 들어간 a,c,i,n,t를 무조건 뽑는다고 생각하고,

 

그리고 주어진 단어들에 있는 단어들 중에서 나머지 K-5개를 뽑는것이다.

 

 

두번째는 각 단어들의 BIT를 비교했던것에서 단어 전체의 bit를 저장해준뒤, 우리가 만든 combination bit와 and 연산을해서, 원래 word_bit가 유지되는지 확인을 해주는 방식이다.

 

이러한 방법을 통해 시간을 줄일 수 있다.

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

[BOJ/백준] 1126 같은 탑  (0) 2021.05.02
[BOJ/백준] 1071 소트  (0) 2021.05.02
[BOJ/백준] 1976 여행 가자  (0) 2021.04.08
[BOJ/백준] 7576 토마토  (0) 2021.04.08
[BOJ/백준] 2812 크게 만들기  (0) 2021.04.08

+ Recent posts