https://www.acmicpc.net/problem/1162
정점의 상태를 잘 정의하고 정의된 정점 간의 간선이 어떻게 이어져있는지를 잘 파악하면 된다.
<문제설명>
양방향 가중치 그래프가 주어진다. 연결된 간선에 대해서 최대 k번 가중치를 0으로 만들 수 있을 때, 정점 1에서 정점n으로 가는 최단길이는?
<풀이>
u번 정점 전까지 도로포장을 t번했다면 정점을 (u,t)로 정의한다 (정점의 상태가 최대 20개라서 가능)
u->v에 대해 (u,t) -> (v,t), (v,t+1) .. t+1<=k 이다.
최대정점 수는 도시수*20 = 2e5이다. -> 다익스트라로 풀 수 있다.
<코드>
typedef pair<ll, ll> P;
typedef pair<ll, P> T;
const int MAX = 1e4 + 2;
const ll INF = 1e18;
vector<P> adj[MAX];
ll dist[MAX][21];
int main() {
FAST;
ll n, m, k; cin >> n >> m >> k;
fill(&dist[0][0], &dist[MAX - 1][21], INF);
dist[1][0] = 0;
for (ll i = 0, u, v, w; i < m; i++) {
cin >> u >> v >> w;
adj[u].push_back({ v,w });
adj[v].push_back({ u,w });
}
bool chk[MAX][21]{ 0 };
priority_queue<T, vector<T>, greater<T>> pq; //dist, (정점)
pq.push({ dist[1][0], {1,0} });
while (!pq.empty()) {
P pp = pq.top().second; pq.pop();
ll curr = pp.first, t = pp.second;
if (chk[curr][t]) continue; //정점이 2차원으로 표현되므로 체크도 2차원
chk[curr][t] = true;
//모든 인접한 정점에 대해
for (P p : adj[curr]) {
ll next = p.first, d = p.second;
if (t <= k - 1) {
if (dist[next][t + 1] > dist[curr][t]) {
dist[next][t + 1] = dist[curr][t];
pq.push({ dist[next][t + 1],{next,t + 1} });
}
}
if (dist[next][t] > dist[curr][t] + d) {
dist[next][t] = dist[curr][t] + d;
pq.push({ dist[next][t],{next,t} });
}
}
}
ll ans = INF;
for (int i = 0; i <= k; i++) ans = min(ans, dist[n][i]);
cout << ans << '\n';
}
'알고리즘 > 백준 & swacademy' 카테고리의 다른 글
BOJ 5719 - 거의 최단 경로 (다익스트라) (0) | 2020.01.27 |
---|---|
BOJ 1854 - K번째 최단경로 찾기(다익스트라) (2) | 2020.01.25 |
BOJ 1176 - 섞기 (bit, dp) (0) | 2020.01.22 |
BOJ 5670 - 새로운 자판 (Trie) (0) | 2020.01.09 |
BOJ 5052 - 전화번호 목록 (Trie) (0) | 2020.01.09 |