티스토리 뷰
요약하면 그래프가 주어지고, Q개의 쿼리에서 X, Y 가 주어지면 X, Y에서 시작하는 스패닝 트리의 최솟값을 구하라는 문제이다. 기존 스패닝 트리와는 다르게 두 점 X, Y에서 스패닝 트리가 시작할 수 있는데 이는 즉, 한 그래프 안에서 스패닝 트리가 2개가 나올 수도 있다는 소리가 된다.
그럼 이를 어떻게 해결할 수 있을까?
그 방법은 스패닝 트리의 특징을 생각해보면 알 수 있다. 스패닝 트리는 N개의 점에 대해 N-1 개의 간선을 가진다.
또 문제에선 X,Y 에서 시작하는 최소 스패닝 트리를 요구하기 때문에 N-1 간선에서 최대 1개의 간선을 제거할 수 있다. 간선을 2개 이상 제거 할 경우, 어떠한 점을 연결할 수 없게 된다. 그러므로 최대 선 1개만 지울 수 있다,
음수 가중치가 없기 때문에 선을 1개를 지우는 것이 0개를 지우는 것보다 최소 값을 만들 수 있는건 자명하다.
또 스패닝 트리를 X,Y 에서 시작하기 때문에 X와 Y는 굳이 연결되어 있을 이유가 없다. 그렇기 때문에 X와 Y를 두 개의 스패닝 트리로 나누는 값이 최소 스패닝 트리를 가지게 된다.(X 혼자 떨어지는 경우도 X 하나의 스패닝 트리라고 본다)
그럼 어떤 선을 지워야지 최소값을 구할 수 있을까?
선을 지우는 방법에는 두가지가 있다.
1. X 와 Y 가 바로 연결되어 있는 경우
2. X 와 Y 가 바로 연결되어 있지 않은 경우
1번의 경우에선 X와 Y를 연결하는 선을 지워야 한다.
그 이유는 간단한데, 선을 1개를 지운다고 했을 때, XY 선이 아닌 다른 선을 지운다면 그 선으로부터 연결된 점들에 X, Y에서 도달하지 못해 스패닝 트리를 이룰 수 없게 된다. 그렇기에 X와 Y를 연결하는 선이 있다는 그 선을 지워야 한다.
2번의 경우에는 선을 지우지 않았을 때의 최소 스패닝 트리 경로에서 DFS 탐색을 통해 X에서 Y 로 가면서 지나간 선의 가중치의 max를 빼주면 된다.
X와 Y 가 연결되어 있지 않고, X와 Y를 2개의 스패닝 트리로 분리해야 되기 때문에 X에서 Y로 가는 선중 가장 큰 가중치를 가지는 선을 지운다면 위 조건을 모두 만족하면서 최솟값을 구할 수 있다.
N의 범위도 1000까지 밖에 되지 않기 때문에 점 마다 DFS 탐색해도 문제없다.
DFS 탐색을 통해 X에서 Y로 가는 구간중 최댓값을 2차원 배열에 저장 후 쿼리 Q마다 전체 최소 스패닝 트리에서 입력에 해당되는 값을 빼주면 된다.
import sys,math
inf=math.inf
sys.setrecursionlimit(10**9)
n,m=map(int,input().split())
uf=[-1]*(n+1)
def find(a):
if uf[a]<0:return a
uf[a]=find(uf[a])
return uf[a]
def merge(a,b):
a=find(a)
b=find(b)
if a==b:return 0
uf[b]=a
return 1
def dfs(x,St,mx):
global x2y_cost
st[x]=1
for i in range(len(mst[x])):
nt=mst[x][i][0]
if st[nt]==0:
x2y_cost[St][nt]=max(mx,mst[x][i][1])
dfs(nt,St,x2y_cost[St][nt])
adj=[]
for i in range(m):
b,c,d=map(int,input().split())
adj.append([d,b,c])
adj.sort()
uf=[-1]*(n+1)
rt=0
cnt=0
mst=[[] for i in range(1005)]
x2y_cost=[[0 for i in range(1002)]for g in range(1002)]
for i in range(m):
u=adj[i][1]
v=adj[i][2]
cost=adj[i][0]
if merge(u,v):
rt+=cost
mst[u].append([v,cost])
mst[u].append([v,cost])
cnt+=1
if cnt==n-1:break
for i in range(n):
st=[0]*(1003)
dfs(i+1,i+1,-inf)
q=int(input())
for i in range(q):
X,Y=map(int,input().split())
print(rt-x2y_cost[X][Y])
'ps' 카테고리의 다른 글
BOJ 2451(모둠) 풀이 (0) | 2023.08.22 |
---|---|
BOJ 2450(모양 정돈) 풀이 (0) | 2023.08.03 |
BOJ 2493(탑) 풀이 (0) | 2023.07.31 |
2023 COI 고등부 예선 풀이 (0) | 2023.05.26 |
BOJ 15480(LCA와 쿼리)풀이 (0) | 2023.05.06 |
- Total
- Today
- Yesterday
- 세그먼트 트리
- 자료 구조
- discord bot
- 구현
- 트리에서의 다이나믹 프로그래밍
- BOJ
- 선분 교차 판정
- 수학
- 그래프 이론
- 정렬
- KOI
- 누적 합
- 깊이 우선 탐색
- 느리게 갱신되는 세그먼트 트리
- codeforces
- 그리디 알고리즘
- 최소 스패닝 트리
- 트리
- 자료구조
- 완전 탐색
- A Dance of Fire and Ice
- 잡봇
- 그래프 탐색
- C++
- Python
- 이분매칭
- 이분 탐색
- 알고리즘
- 개발
- 다이나믹 프로그래밍
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |