https://www.acmicpc.net/problem/2668
2668번: 숫자고르기
세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절
www.acmicpc.net
숫자고르기
1 초 | 128 MB | 13024 | 5660 | 4469 | 45.260% |
문제
세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절히 뽑으면, 그 뽑힌 정수들이 이루는 집합과, 뽑힌 정수들의 바로 밑의 둘째 줄에 들어있는 정수들이 이루는 집합이 일치한다. 이러한 조건을 만족시키도록 정수들을 뽑되, 최대로 많이 뽑는 방법을 찾는 프로그램을 작성하시오. 예를 들어, N=7인 경우 아래와 같이 표가 주어졌다고 하자.

이 경우에는 첫째 줄에서 1, 3, 5를 뽑는 것이 답이다. 첫째 줄의 1, 3, 5밑에는 각각 3, 1, 5가 있으며 두 집합은 일치한다. 이때 집합의 크기는 3이다. 만약 첫째 줄에서 1과 3을 뽑으면, 이들 바로 밑에는 정수 3과 1이 있으므로 두 집합이 일치한다. 그러나, 이 경우에 뽑힌 정수의 개수는 최대가 아니므로 답이 될 수 없다.
입력
첫째 줄에는 N(1≤N≤100)을 나타내는 정수 하나가 주어진다. 그 다음 줄부터는 표의 둘째 줄에 들어가는 정수들이 순서대로 한 줄에 하나씩 입력된다.
출력
첫째 줄에 뽑힌 정수들의 개수를 출력하고, 그 다음 줄부터는 뽑힌 정수들을 작은 수부터 큰 수의 순서로 한 줄에 하나씩 출력한다.
예제 입력 1 복사
7
3
1
1
5
5
4
6
예제 출력 1 복사
3
1
3
5
풀이 (틀린 풀이 _ 백트래킹)
import sys
input = sys.stdin.readline
n = int(input())
# 2차원 리스트 (인덱스 0은 윗줄, 1은 아랫줄)
graph = [[i] for i in range(n+1)]
for i in range(1, n+1):
graph[i].append(int(input()))
visited = [False]*(n+1)
answer = -1e9
answer_list = []
def dfs(upper, lower):
global answer, answer_list
if len(upper) != 0:
flag = True
for i in range(0, len(upper)):
if upper[i] not in lower:
flag = False
break
if flag == True:
if answer < len(upper):
answer_list = upper
answer = max(len(upper), answer)
for i in range(1, n+1):
if not visited[i]:
visited[i] = True
dfs(upper+[i], lower+[graph[i][1]])
visited[i] = False
dfs([], [])
print(answer)
answer_list.sort()
for i in answer_list:
print(i)
처음에 단순 백트래킹으로 풀었다.
하지만 시간초과로 실패 ㅠㅠ
풀이 (정답 참고 _ 사이틀 이용)
첫째줄, 둘째줄의 연결된 그래프로 생각하고 정답 후보들을 살펴보면 사이클을 형성하는 것을 알 수 있다.
참고 : https://jjunohj.github.io/boj/boj-2668/
[BOJ] 백준 2668번 - 숫자고르기 (Python)
Gold 5
jjunohj.github.io
# 입력
n = int(input())
graph = [[] for i in range(n + 1)]
for i in range(1, n + 1):
graph[i].append(int(input()))
def dfs(s):
global result, cnt
visited[s] = True # 방문 처리
for now in graph[s]:
# 방문 안했을 경우 방문, 재귀
if visited[now] == False:
dfs(now)
# 방문했는데 안끝났을 경우, 역방향 간선 확인
elif visited[now] == True and finished[now] == False:
if now not in result: # result에 중복 삽입 방지
cnt += 1
result.append(now)
return
else:
return
finished[s] = True # 함수 종료
result = []
cnt = 0
# 각각의 노드마다 루트 노드로서 반복해주어야 한다.
for i in range(1, n + 1):
visited = [False] * (n + 1)
finished = [False] * (n + 1)
dfs(i)
result.sort()
print(cnt)
for i in result:
print(i)
(코드 복습 필요)
'알고리즘 > Baekjoon' 카테고리의 다른 글
[BOJ] 18111 마인크래프트 Python (복습 필요) (0) | 2023.02.14 |
---|---|
[BOJ] 2468 안전 영역 Python (0) | 2023.02.12 |
[programmers] 여행경로 Python (0) | 2023.02.08 |
[BOJ] 상범 빌딩 Python (0) | 2023.02.08 |
[BOJ] 2660 회장뽑기 Python (0) | 2023.02.07 |