[파이썬, 자바] 백준 28707 : 배열 정렬 (골드1)
풀이
방향성 생각
- 입력에 들어오는 숫자가 1부터 10이라 문자열로 변환하면 10이 인덱스 크기에 영향을 줄 수 있다.
- 입력에 숫자가 들어올 때 -1을 빼주기.
- 쿼리도 인덱스를 맞춰주기 위해 l,r에 각각 1씩 빼주기.
- 리스트/배열 저장 대신 문자열로 변환해서 set에 저장하기.
- 간선 크기가 달라서 BFS 대신 다익스트라 사용
파이썬
# defaultdict로 초기값 INF로 저장장
from collections import defaultdict as dd
import heapq as hq
INF = float('inf')
N = int(input())
arr = list(map(lambda x : str(int(x)-1),input().split()))
# operations 인덱스 맞춰주기
M = int(input())
ops = []
for _ in range(M):
a,b,cost = map(int,input().split())
ops.append((a-1,b-1,cost))
# 다익스트라
def di():
# 문자열로 바꿔서 방문처리리
V = dd(lambda : INF)
V[''.join(arr)] = 0
heap = [(0,''.join(arr))]
while heap:
t,string = hq.heappop(heap)
# 내림차순인지 확인하기기
non_desc = True
for i in range(1,N):
if string[i-1] > string[i]:
non_desc = False
break
if non_desc:
return t
# 인덱스 기반
for a,b,cost in ops:
nstring = ''
nt = t+cost
for i in range(N):
if i == b:
nstring += string[a]
elif i == a:
nstring += string[b]
else:
nstring += string[i]
# 갱신 가능하면 힙에 추가
if nt < V[nstring]:
V[nstring] = nt
hq.heappush(heap,(nt,nstring))
return -1
print(di())
- 문자열이나 튜플로 저장해야하는데, 어짜피 튜플도 수정 불가능해서 문자열로 사용
- 물통 채우는 문제로 비슷하게 state를 string이나 tuple로 만들어서 저장하는 문제들이 많았는데, BFS에서 간선에 가중치만 추가된 다익스트라 문제.
자바
import java.io.*;
import java.util.*;
public class Main {
static final int INF = Integer.MAX_VALUE;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < N; i++) {
sb.append((char) (Integer.parseInt(st.nextToken()) - 1 + '0'));
}
String startState = sb.toString();
int M = Integer.parseInt(br.readLine());
int[][] ops = new int[M][3];
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
ops[i][0] = Integer.parseInt(st.nextToken()) - 1;
ops[i][1] = Integer.parseInt(st.nextToken()) - 1;
ops[i][2] = Integer.parseInt(st.nextToken());
}
System.out.println(di(startState, ops, N));
}
static int di(String startState, int[][] ops, int N) {
HashMap<String, Integer> V = new HashMap<>();
PriorityQueue<Node> pq = new PriorityQueue<>((n1, n2) -> Integer.compare(n1.t, n2.t));
V.put(startState, 0);
pq.offer(new Node(0, startState));
while (!pq.isEmpty()) {
Node cur = pq.poll();
int t = cur.t;
String string = cur.string;
if (V.get(string) < t)
continue;
boolean nonDesc = true;
for (int i = 1; i < N; i++) {
if (string.charAt(i - 1) > string.charAt(i)) {
nonDesc = false;
break;
}
}
if (nonDesc) {
return t;
}
for (int[] op : ops) {
int a = op[0];
int b = op[1];
int cost = op[2];
char[] nchars = string.toCharArray();
char temp = nchars[a];
nchars[a] = nchars[b];
nchars[b] = temp;
String nstring = new String(nchars);
int nt = t + cost;
if (!V.containsKey(nstring) || nt < V.get(nstring)) {
V.put(nstring, nt);
pq.offer(new Node(nt, nstring));
}
}
}
return -1;
}
static class Node {
int t;
String string;
public Node(int t, String string) {
this.t = t;
this.string = string;
}
}
}
- arr을 int로 받아서 toString으로 문자열 생성하기
- arr을 char로 받아서 new String(arr)로 문자열 생성하기
- heap에 넣을 자료타입이 달라서 전달용 Node 클래스 만들기.
- 문자열 변환에서도 string builder로 만들어서 set char at 사용하거나, char[] 배열 만들어서 스왑하거나 둘 중 하난데, 메서드보단 기본적으로 사용되는 방식으로 구현하기.
- defaultdict 구현에서는 containsKey + get을 사용해서 값이 있는 경우에 값 가져오기.
코멘트
- 전달용 클래스 만드는게 극혐임
- 티어뻥이 좀 있는듯?
'Algorithm > Graph' 카테고리의 다른 글
[파이썬] 백준 15906 : 변신 이동 게임 (골드1) (0) | 2025.03.03 |
---|---|
[파이썬] 백준 10776 : 제국 (골드1) (0) | 2025.03.02 |
[파이썬] 백준 18224 : 미로에 갇힌 건우 (골드1) (0) | 2025.03.01 |
[파이썬] 백준 16118 : 달빛 여우 (골드1) (0) | 2025.02.24 |
[파이썬, 자바] 백준 1559 : 놀라운 미로 (플레5) (0) | 2025.02.23 |
[파이썬] 백준 11657 : 타임머신 (골드4) (1) | 2025.02.19 |
[파이썬] 백준 1865 : 웜홀 (골드3) (0) | 2025.02.19 |
댓글