반응형

https://www.acmicpc.net/problem/1162

 

1162번: 도로포장

첫 줄에는 도시의 수 N(1 ≤ N ≤ 10,000)과 도로의 수 M(1 ≤ M ≤ 50,000)과 포장할 도로의 수 K(1 ≤ K ≤ 20)가 공백으로 구분되어 주어진다. M개의 줄에 대해 도로가 연결하는 두 도시와 도로를 통과하

www.acmicpc.net

 

다익스트라 알고리즘을 이용하여 풀이하였습니다.

dp[i][j] = 1번 도시에서 i번 도시로 갈 때, j개의 도로를 포장하여 얻을 수 있는 최소 비용입니다.

다익스트라를 수행하며, 도로를 포장했을 때와 도로를 포장하지 않았을 때의 두 가지 경우를 모두 우선순위 큐에 넣어줍니다.

priority_queue<plii> pq; // {cost, city, k}
dp[1][0] = 0;
pq.push({ 0, {1, 0} });
while (!pq.empty()) {
	ll c = -pq.top().first;
	int x = pq.top().second.first;
	int kk = pq.top().second.second;
	pq.pop();

	if (dp[x][kk] < c) continue;

	for (auto& p : graph[x]) {
		int nxt = p.first;
		int cost = p.second;
		if(kk < k) updateIfGreater(pq, nxt, kk + 1, c); // 도로를 포장하는 경우
		updateIfGreater(pq, nxt, kk, c + cost); // 도로를 포장하지 않는 경우
	}
}

위와 같이 아직 k개의 도로를 포장하지 않았다면, 두 가지 경우를 모두 검사하여 우선순위 큐와 dp 배열을 업데이트해줍니다.

 

updateIfGreater는 중복된 코드라 따로 함수로 추출하였는데,

void updateIfGreater(priority_queue<plii>& pq, int nxt, int kk, ll nxtCost) {
	if (dp[nxt][kk] > nxtCost) {
		dp[nxt][kk] = nxtCost;
		pq.push({ -nxtCost, {nxt, kk} });
	}
}

단순히 dp와 pq를 업데이트해주는 함수입니다.

 

 

이렇게 얻은 dp 배열로, dp[n][0] ~ dp[n][k] 에서의 최솟값을 구해주면 K개 이하의 도로를 포장하여 얻을 수 있는 최소 비용을 구할 수 있습니다.

ll mn = dp[n][0];
for (int i = 1; i <= k; i++) {
	mn = min(mn, dp[n][i]);
}
cout << mn;

처음 단순하게 생각했을 때는, 무조건 더 많은 도로를 포장하는게 더욱 이득이지 않을까 싶어서,

dp[n][k]가 최소 비용을 보장할지 고민해보았는데, 안일한 생각이었습니다.

4 4 2
1 2 10
2 3 10
3 4 10
1 4 20

다음과 같은 경우가 있다면, 1-4 도로 1개만 포장된 경로로 이동하는 것이 최소 비용이 됩니다. 

 

늘 문제를 제대로 읽지 않아서 한 번씩 헤매곤 하는데, 주어진 도로 입력은 양방향임을 유의해야했습니다.

 

전체 소스코드는 다음과 같습니다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstring>
#define N_MAX 10001
#define K_MAX 21
using namespace std;

typedef long long int ll;
typedef pair<int, int> pii;
typedef pair<ll, pii> plii;

int n, m, k, a, b, c;
vector<pii> graph[N_MAX];
ll dp[N_MAX][K_MAX];

void pushIfGreater(priority_queue<plii>& pq, int nxt, int kk, ll nxtCost) {
	if (dp[nxt][kk] > nxtCost) {
		dp[nxt][kk] = nxtCost;
		pq.push({ -nxtCost, {nxt, kk} });
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	memset(dp, 0x77, sizeof(dp));

	cin >> n >> m >> k;

	while (m--) {
		cin >> a >> b >> c;
		graph[a].push_back({ b, c });
		graph[b].push_back({ a, c });
	}

	priority_queue<plii> pq; // {cost, city, k}
	dp[1][0] = 0;
	pq.push({ 0, {1, 0} });
	while (!pq.empty()) {
		ll c = -pq.top().first;
		int x = pq.top().second.first;
		int kk = pq.top().second.second;
		pq.pop();

		if (dp[x][kk] < c) continue;

		for (auto& p : graph[x]) {
			int nxt = p.first;
			int cost = p.second;
			if(kk < k) pushIfGreater(pq, nxt, kk + 1, c);
			pushIfGreater(pq, nxt, kk, c + cost);
		}
	}

	ll mn = dp[n][0];
	for (int i = 1; i <= k; i++) {
		mn = min(mn, dp[n][i]);
	}
	cout << mn;
}
반응형

'Algorithm' 카테고리의 다른 글

백준 1781 : 컵라면  (0) 2021.12.25
백준 2629 : 양팔저울  (0) 2021.11.24
백준 11780 : 플로이드 2  (0) 2021.11.23
백준 16064 : Coolest Ski Route  (0) 2021.11.22
백준 2660 : 회장뽑기  (0) 2021.11.22

+ Recent posts