Hello Kitty Eyes Shut
λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ’» μ½”ν…Œ/πŸ“Œ Python

[μ½”ν…Œ/Python] μ„ΈκΈˆ μ§•μˆ˜

λ°˜μ‘ν˜•

 

 

 

 

πŸ“‘ 문제

  • λ°©ν–₯ κ·Έλž˜ν”„κ°€ 있고, 각 κ°„μ„ μ—λŠ” ν†΅ν–‰λ£Œ d 와 폐쇄 λΉ„μš© c κ°€ λΆ™μ–΄ μžˆλ‹€.
  • μ‹œμž‘μ  s μ—μ„œ 도착점 e 둜 κ°€λŠ” 총 ν†΅ν–‰λ£Œκ°€ x μ΄ν•˜μΈ λͺ¨λ“  κ²½λ‘œμ— ν¬ν•¨λ˜λŠ” 간선을 μ „λΆ€ νμ‡„ν•˜λ € ν•œλ‹€.
  • μ—¬λŸ¬ 질의 x 에 λŒ€ν•΄μ„œ 폐쇄해야 ν•  κ°„μ„ λ“€μ˜ 폐쇄 λΉ„μš© 합을 ꡬ해야 ν•œλ‹€.

 

 


πŸ’‘ 아이디어

핡심은 κ°„μ„  λ‹¨μœ„λ‘œ κ·Έ 간선을 μ§€λ‚˜λŠ” s -> e 경둜의 μ΅œμ†Œ 톡행렀λ₯Ό ν•œ λ²ˆμ— κ³„μ‚°ν•΄λ‘λŠ” 것이닀.

이 값을 미리 μ•Œλ©΄ 질의 xλ§ˆλ‹€ μž„κ³„κ°‘ μ΄ν•˜μΈ κ°„μ„ λ§Œ ν•©μ‚°ν•˜λ©΄ 되기 λ•Œλ¬Έμ— νš¨μœ¨μ μ΄λ‹€.

 

  1. κ°„μ„ λ§ˆλ‹€ μ΅œμ†Œ λΉ„μš© κ³„μ‚°ν•˜κΈ°
    λ§Œμ•½ μ–΄λ–€ λ„λ‘œ u -> v κ°€ μžˆλ‹€κ³  ν•΄λ³΄μž.
    이 λ„λ‘œκ°€ μ‹€μ œλ‘œ s - > e κ²½λ‘œμ— ν¬ν•¨λ˜λ €λ©΄, μ•„λž˜μ˜ 3κ°€μ§€ μš”μ†Œλ₯Ό λͺ¨λ‘ λ”ν•΄μ€˜μ•Ό ν•œλ‹€.
    1) sμ—μ„œ uκΉŒμ§€ κ°€λŠ” μ΅œλ‹¨ μš”κΈˆ
    2) u -> v λ„λ‘œμ˜ μš”κΈˆ
    3) vμ—μ„œ eκΉŒμ§€ κ°€λŠ” μ΅œλ‹¨ μš”κΈˆ
    πŸ‘‰πŸ» 즉, μœ„μ˜ μ„Έ κ°€μ§€λ₯Ό 더해주면, ν•΄λ‹Ή λ„λ‘œ(u -> v)λ₯Ό 거쳐 s - > e둜 κ°€λŠ” 데 λ“œλŠ” μ΅œμ†Œ μš”κΈˆμ„ μ•Œ 수 μžˆλŠ” 것이닀.
         (μ‰½κ²Œ 말해 λ„λ‘œ ν•˜λ‚˜λ§ˆλ‹€ 이 λ„λ‘œλ₯Ό κ±°μΉ˜λŠ” μ΅œμ € 경둜 μš”κΈˆμ„ 미리 μ μ–΄λ‘λŠ” 거라고 μƒκ°ν•˜λ©΄ λœλ‹€.)
  2. μž„κ³„κ°’ x와 λΉ„κ΅ν•˜κΈ°
    μœ„μ—μ„œ κ³„μ‚°ν•œ 값을 key(κ°„μ„ )이라 ν•˜κ³ , 질의 xκ°€ λ“€μ–΄μ˜¨λ‹€κ³  ν•˜μž.
    1) λ§Œμ•½ key <= x 이면 πŸ‘‰πŸ» 이 λ„λ‘œλŠ” μ–΄λ–€ κ²½λ‘œμ—μ„œλ“  총 μš”κΈˆμ΄ x μ΄ν•˜μΌ κ°€λŠ₯성이 μžˆμœΌλ‹ˆ, 폐쇄 후보가 됨
    2) λ§Œμ•½ key > x 이면 πŸ‘‰πŸ» μ• μ΄ˆμ— 이 λ„λ‘œλ₯Ό μ§€λ‚˜λŠ” μˆœκ°„ λΉ„μš©μ΄ 폐쇄 μž„κ³„κ°’ 보닀 μ»€μ§€λŠ” κ²ƒμ΄λ―€λ‘œ, 폐쇄될 일이 μ—†μŒ
  3. μ—¬λŸ¬ 질의λ₯Ό λΉ λ₯΄κ²Œ μ²˜λ¦¬ν•˜κΈ°
    μ—¬λŸ¬ 개의 x 값이 λ“€μ–΄μ˜¬ 수 μžˆμœΌλ‹ˆκΉŒ, 맀번 λͺ¨λ“  λ„λ‘œλ₯Ό λ‹€ 확인해주면 λ„ˆλ¬΄ λŠλ¦¬λ‹€.
    κ·Έλž˜μ„œ μš°λ¦¬λŠ” 미리 μ•„λž˜μ˜ 쀀비듀을 ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.
    1) λͺ¨λ“  λ„λ‘œμ˜ (key, 폐쇄 λΉ„μš©)을 적어놓고, keyλ₯Ό κΈ°μ€€μœΌλ‘œ μ •λ ¬ν•œλ‹€.
    2) 폐쇄 λΉ„μš©λ“€μ„ μœ„μ—μ„œλΆ€ν„° μ°¨λ‘€λŒ€λ‘œ λ”ν•΄μ„œ λˆ„μ ν•©μ„ λ§Œλ“€μ–΄μ€€λ‹€.
        (ex. μ•žμ—μ„œλΆ€ν„° 3개의 λ„λ‘œλ₯Ό ν•©μΉ˜λ©΄ λΉ„μš©μ΄ μ–Όλ§ˆκ³ , 5개의 λ„λ‘œλ₯Ό ν•©μΉ˜λ©΄ λΉ„μš©μ΄ μ–Όλ§ˆκ³  .. 이런 λŠλ‚Œ)
    3) 이제 질의 xκ°€ λ“€μ–΄μ˜€λ©΄, key <= x 인 λ„λ‘œκ°€ λͺ‡ κ°œμΈμ§€λ§Œ 이뢄 νƒμƒ‰λ‘œ μ°Ύκ³ , κ·Έ κ°œμˆ˜κΉŒμ§€μ˜ λˆ„μ ν•©μ„ λ‹΅μœΌλ‘œ λ°”λ‘œ κΊΌλ‚΄λ©΄ λœλ‹€.

 

 

더 μ‰½κ²Œ μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œ μ•„μ˜ˆ λ‹€λ₯Έ 상황을 μƒκ°ν•΄λ³΄μž.

 

λ§Œμ•½ λ‚΄κ°€ μ§€κΈˆ λ§ˆνŠΈμ— κ°€μ„œ 쇼핑을 ν•˜κ³  μžˆλŠ”λ°,

각 μƒν’ˆλ§ˆλ‹€ 'μ΄κ±°λŠ” μ΅œμ†Œ key원 이상 사야 ꡬ맀 κ°€λŠ₯함, ν•˜λ‚˜ λ‹Ή 가격은 cost원 μž„' 이라고 μ¨μžˆλ‹€κ³  ν•΄λ³΄μž.

 

λ‚˜λŠ” 였늘 쇼핑을 λ‚˜μ˜€λ©΄μ„œ xμ›λ§Œ λ“€κ³  μ™”λ‹€κ³  ν•˜λ©΄,

key < = x μ΄ν•˜μΈ μƒν’ˆλ“€ μ€‘μ—μ„œλ§Œ 쇼핑을 ν•  수 μžˆμ„ 것이닀.

(μ΅œμ†Œ x원 이상 사야 ꡬ맀가 κ°€λŠ₯ν•œ μƒν’ˆμ„ 골라야 λ‚΄κ°€ λˆμ„ λ‚Ό 수 μžˆμœΌλ‹ˆκΉŒ ..)

 

κ΅¬μ²΄μ μœΌλ‘œλŠ”, λ‚΄κ°€ 였늘 λ§Œμ›μ„ λ“€κ³  쇼핑을 ν•˜λ €κ³  λ‚˜μ™”λŠ”λ°,

라면은 ν•œ 봉지당 5μ²œμ›(cost)인데, λ§Œμ›(key) 이상 사야 κ²°μ œκ°€ κ°€λŠ₯ν•˜λ‹€κ³  ν•˜κ³ ,

λ–‘λ³Άμ΄λŠ” ν•œ 봉지당 8000(cost) 원인데, 만 μ˜€μ²œμ›(key) 이상 사야 κ²°μ œκ°€ κ°€λŠ₯ν•˜λ‹€κ³  ν•΄λ³΄μž.

그러면 λ‚΄κ°€ κ°€μ§„ λˆμ€ λ§Œμ› 뿐인데,

떑볢이λ₯Ό 사렀면 μ΅œμ†Œ 만 μ˜€μ²œμ›μ΄ ν•„μš”ν•œ κ±°λ‹ˆκΉŒ μ• μ΄ˆμ— λ‚œ 떑볢이λ₯Ό μ‚¬λŠ”κ²Œ λΆˆκ°€λŠ₯ν•΄μ§„λ‹€.

 

 

κ·Έλž˜μ„œ λ‚΄κ°€ keyλ₯Ό κΈ°μ€€μœΌλ‘œ 정렬을 ν•΄μ€€ 것이고,

ꡬ맀 κ°€λŠ₯ν•œ μ΅œμ†Œ μš”κΈˆ 5μ²œμ›, μ΅œμ†Œ μš”κΈˆ 8μ²œμ›, μ΅œμ†Œ μš”κΈˆ λ§Œμ›, μ΅œμ†Œ μš”κΈˆ 3λ§Œμ› , ... 이런 λŠλ‚ŒμœΌλ‘œ 정렬이 λ˜μ—ˆλ‹€κ³  치면,

λ‹€λ₯Έ μ†λ‹˜μ΄ μ™€μ„œ 'μ €λŠ” 였늘 x원 κΉŒμ§€λ§Œ μ“Έλž˜μš”~' ν–ˆμ„ λ•Œ, λ°”λ‘œ ꡬ맀 κ°€λŠ₯ν•œ μƒν’ˆλ“€μ„ λŒ€λ‹΅ν•  수 있게 λ˜λŠ” 것이닀.

 


πŸ‘©πŸ»‍πŸ’» 전체 μ½”λ“œ

from heapq import heappush, heappop

INF = 10**9

# λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜
# startλŠ” μ‹œμž‘ 정점
# graphλŠ” 인접 리슀트 (graph[u] = (v, w))
# n은 μ •μ μ˜ 개수
def dijkstra(start, graph, n):
	dist = [INF] * n   # μ΅œλ‹¨ 거리 λ°°μ—΄
	dist[start] = 0
	pq = [(0, start)]  # (거리, 정점) μš°μ„ μˆœμœ„ 큐

	while pq:
		du, u = heappop(pq)
        
        # 이미 더 짧은 μ΅œλ‹¨ 거리가 κ°±μ‹ λœ κ²½μš°λŠ” κ±΄λ„ˆλ›°κΈ°
		if du != dist[u]:
			continue
            
        # uμ—μ„œ λ‚˜κ°ˆ 수 μžˆλŠ” λͺ¨λ“  κ°„μ„  κ²€μ‚¬ν•˜κΈ°
		for v, w in graph[u]:
			nd = du + w
			if nd < dist[v]:
				dist[v] = nd
				heappush(pq, (nd, v))
	return dist



def main():

	# n은 정점 수, m은 κ°„μ„  수, sλŠ” μ‹œμž‘ 정점, eλŠ” 도착 정점
	n, m, s, e = map(int, input().split())
	s -= 1
	e -= 1

	# μ •λ°©ν–₯ κ·Έλž˜ν”„μ™€ μ—­λ°©ν–₯ κ·Έλž˜ν”„ 쀀비해두기
	not_reverse = [[] for _ in range(n)] # s -> ... νƒμƒ‰μš©
	reverse = [[] for _ in range(n)]     # ... -> e νƒμƒ‰μš©

	edge = [] # 원본 κ°„μ„  (u, v, d, c) μ €μž₯용

	# κ°„μ„  μž…λ ₯ λ°›κΈ°
	for _ in range(m):
		u, v, d, c = map(int, input().split())
		u -= 1
		v -= 1
		
        # μ •λ°©ν–₯ u -> v (λΉ„μš© d)
		not_reverse[u].append((v, d))
        # μ—­λ°©ν–₯ v -> u (λΉ„μš© d)
		reverse[v].append((u, d))
        # μš°λ„ˆλ³Έ κ°„μ„  μ €μž₯
		edge.append((u, v, d, c))

	# 질의 μž…λ ₯
	q = int(input())
	qs = [int(input()) for _ in range(q)]

	
	distS = dijkstra(s, not_reverse, n) # sμ—μ„œ 각 μ •μ κΉŒμ§€μ˜ μ΅œλ‹¨ 거리
	distE = dijkstra(e, reverse, n)     # 각 μ •μ μ—μ„œ eκΉŒμ§€μ˜ μ΅œλ‹¨ 거리

	# 각 κ°„μ„  λ³„λ‘œ "s->u + d + v->e" μ΅œμ†Œ λΉ„μš©(key) 계산
	keys = []  # κ°„μ„ μ˜ μ΅œμ†Œ 경둜 λΉ„μš©
	costs = [] # κ°„μ„  폐쇄 λΉ„μš©

	for u, v, d, c in edge:
    	# sμ—μ„œ uκΉŒμ§€, vμ—μ„œ eκΉŒμ§€ 도달 λΆˆκ°€λŠ₯ν•˜λ©΄ κ±΄λ„ˆλ›°κΈ°
		if distS[u] == INF or distE[v] == INF:
			continue

		key = distS[u] + d + distE[v] # ν•΄λ‹Ή 간선을 μ§€λ‚˜λŠ” μ΅œμ†Œ 경둜 λΉ„μš©
		keys.append(key)
		costs.append(c)

	# (key, cost) 쌍 μ •λ ¬ μ€€λΉ„
	pairs = []
	i = 0
	while i < len(keys):
		pairs.append((keys[i], costs[i]))
		i += 1

	# key κΈ°μ€€ μ •λ ¬
	pairs.sort()

	# key와 λΉ„μš©λ§Œ λ”°λ‘œ 뢄리
	sorted_keys = []
	i = 0
	while i < len(pairs):
		sorted_keys.append(pairs[i][0])
		i += 1

	# λˆ„μ  λΉ„μš© ν•© λ°°μ—΄
	sums = [0]
	accumulate = 0
		
	i = 0
	while i < len(pairs):
		accumulate += pairs[i][1]
		sums.append(accumulate)
		i += 1

	# upper bound: x μ΄ν•˜μ˜ key 개수 μ°ΎκΈ°
	def upper(arr, x):
		l = 0
		h = len(arr)

		while l < h:
			mid = (l + h) // 2
			if arr[mid] <= x:
				l = mid + 1
			else:
				h = mid
		return l

	# 각 질의 처리
	ans = []
	i = 0
	while i < len(qs):
		x = qs[i]
        # key <= x 인 κ°„μ„  개수 κ΅¬ν•˜κΈ°
		k = upper(sorted_keys, x)
        # λˆ„μ ν•©μ—μ„œ ν•΄λ‹Ή κ΅¬κ°„κΉŒμ§€ λΉ„μš© ν•© 좜λ ₯
		ans.append(str(sums[k]))
		i += 1

	print("\n".join(ans))



if __name__ == "__main__":
	main()

 

 


πŸ“š κ²°λ‘ 

보톡 μ•žμ„œ 올렸던 3번 dp 문제(λ„ν˜• λ§Œλ“€κΈ°)λ₯Ό 더 μ–΄λ €μ›Œν•˜λ˜λ°,

λ‚œ μ˜€λžœλ§Œμ— μ½”ν…Œλ₯Ό λ΄μ„œ κ·ΈλŸ°κ°€ 이 λ¬Έμ œκ°€ 더 였래 고민됐닀 ..

(별건 μ•„λ‹ˆμ§€λ§Œ μ–΄λ–»κ²Œ μ ‘κ·Όν–ˆλŠ”μ§€κ°€ κ°€λ¬Όκ°€λ¬Όν•΄μ„œ ..γ…œγ…œ)

 

κ·Έλž˜λ„ μ˜€λžœλ§Œμ— 문제λ₯Ό κ°„μ„  λ‹¨μœ„λ‘œ μͺΌκ°œμ„œ, μ „μ²˜λ¦¬λ‘œ κ΅¬μ‘°ν™”ν•œ λ’€,

효율적으둜 질의λ₯Ό μ²˜λ¦¬ν•˜λŠ” 사고법을 λ– μ˜¬λ €λ³΄λ‹ˆ λΏŒλ“―ν•˜κΈ΄ ν–ˆμ§€λ§Œ 머리가 λ„ˆλ¬΄ μ•„νŒ λ‹€ .. ^^ ..

 

μž κΉμ΄λΌλ„ μ†Œν™€νžˆ ν•˜λ©΄ 머리가 κΈ‰κ²©ν•˜κ²Œ κ΅³μ–΄λ²„λ¦°λ‹€λŠ” 것을 κΉ¨λ‹¬μ•˜μœΌλ‹ˆ

μ•žμœΌλ‘œλŠ” μ½”ν…Œλ„ κΎΈμ€€νžˆ ν’€μ–΄μ„œ ν¬μŠ€νŒ…ν•΄μ•Όκ² λ‹€. (κΌ­ !!!! πŸ‘ŠπŸ»πŸ‘ŠπŸ»πŸ‘ŠπŸ»πŸ‘ŠπŸ»)

λ°˜μ‘ν˜•