11657번 - 타임머신
문제 풀이 시간 : 1시간
문제 요약
- N개의 도시가 있다.
- 한 도시에서 출발해 다른 도시에 도착하는 버스 M개가 있다.
- 각 버스는 A,B,C로 나타낸다.
- A-시작도시, B-도착도시, C-걸리는 시간
- C는 양수가 아닐 수 있다.
- C=0 : 순간이동, C<0 타임머신 이동
- 1번 도시에서 출발해 나머지 도시로 가는 가장 빠른 시간 구해라
문제 풀이
처음 이 문제를 보고 나는 바로 다익스트라로 풀어야겠다는 생각으로 바로 코드를 짰다.
초기 코드
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int n, m;
vector<pair<int, int>> v[501];
int arr[501];
bool find() {
priority_queue<pair<int, int>> pq;
pq.push({0, 1});
arr[1] = 0;
while (!pq.empty()) {
int node = pq.top().second;
int dist = -pq.top().first;
pq.pop();
if (node == 1 && arr[node] < 0)
return false;
if (arr[node] < dist)
continue;
for (int i = 0; i < v[node].size(); i++) {
int next = v[node][i].first;
int ndis = v[node][i].second + dist;
if (arr[next] > ndis) {
arr[next] = ndis;
pq.push({-ndis, next});
}
}
}
return true;
}
int main() {
cin >> n >> m;
int a, b, c;
for (int i = 0; i < m; i++) {
cin >> a >> b >> c;
v[a].push_back({b, c});
}
for (int i = 1; i <= n; i++) {
arr[i] = 10000000;
}
if (find()) {
for (int i = 2; i <= n; i++) {
if (arr[i] == 10000000)
cout << -1 << "\n";
else
cout << arr[i] << "\n";
}
} else
cout << -1;
}테스트 케이스를 다 정상적으로 동작을 하길래
아 껌이네..
하고 바로 제출을 했더니
메모리 초과가 나온다.
벡터와 배열이랑 이것저것 메모리를 여러개 사용해서 그런 것 같다.
근데 이걸 그렇게 안하면 도저히 해결방법이 생각이 안나서
결국 찾아봤더니
이게뭐람..
애초에 다익스트라로 푸는 문제가 아니었다.
벨만포드 알고리즘이라는 것을 사용해야했다.
벨만포드 알고리즘은 다익스트라와 비슷하지만
다익스트라는 매 반복마다 최단거리가 가장 짧은 노드 하나만 선택해서 찾지만
벨만포드는 매 반복마다 모든 간선을 다 확인한다.
그렇게 해서 코드를 다시짜면
최종 코드
#include <iostream>
#include <vector>
#include <queue>
#define INF 1e9 //최댓값 설정
using namespace std;
int n, m;
vector<pair<int, pair<int, int>>> v;
long long arr[501];
bool find() {
arr[1] = 0;
for (int i = 1; i <= n; i++) { //n번 반복(n-1번 + 마지막 확인을 위한 1번)
for (int j = 0; j < m; j++) { //각 노드 반복
int from = v[j].first; //시작 노드
int next = v[j].second.first; //다음 노드
long long dist = v[j].second.second; //거리
if (arr[from] == INF) //방문되지 않았다면 통과
continue;
if (arr[next] > arr[from] + dist) { //거리 업데이트 가능하면 업데이트
arr[next] = arr[from] + dist;
if (i == n) //n번째 반복에도 업데이트가 일어나면 음수 사이클 존재
return false;
}
}
}
return true;
}
int main() {
cin >> n >> m;
int a, b, c;
for (int i = 0; i < m; i++) {
cin >> a >> b >> c;
v.push_back({a, {b, c}});
}
for (int i = 1; i <= n; i++) {
arr[i] = INF;
}
if (find()) {
for (int i = 2; i <= n; i++) {
if (arr[i] == INF)
cout << -1 << "\n";
else
cout << arr[i] << "\n";
}
} else
cout << -1;
}함께 읽으면 좋은 글
2186번 - 문자판
알파벳 문자가 한칸에 하나씩 적혀있는 NxM크기의 문자판이 있다. 임의의 칸에서 시작하여 상하좌우 K개의 칸까지 이동하며 문자를 모은다. 반드시 한 칸 이상 이동하며, 같은 자리에 머물 수 없다. 같은 칸을 여러 번 방문할 수 있다.
16234번 - 인구 이동
NxN크기의 땅 한칸마다 나라가 존재한다. 국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하라면 두 나라는 연합이 된다. 위의 조건에 해당하는 모든 나라가 연합이 되었다면 그 연합은 인구이동을 한다.
2096번 - 내려가기
n줄에 0이상 9이하의 숫자가 세개씩 적혀있다. 첫줄에서 가장 마지막줄까지 이동하면서 세가지 숫자 중 하나를 고른다. 마지막 줄에서 얻을 수 있는 최대 점수, 최소 점수를 구해라 이 문제는 dp로 풀 수 있겠다고 생각했다.
5525번 - IOIOI
n+1개의 I와 n개의 O로 이루어진 문자열이 있다. (IOIOI…) I,O로 이루언진 문자열 S가 주어졌을 때, S안에 위의 문자열이 몇번 포함되어 있는지 구해라 위 코드는 50점을 받았다.