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



배열 돌리기 목록을 꼭 "모두 사용해야 한다"고 했다. 또한 배열을 돌리는 순서에 따라서 결과가 달라지기 때문에, 순열을 사용해서 돌릴 순서를 정해준다.


모든 경우를 다 돌려봐야 하고, 주의할 사항은, 한 순열을 돌린 이후에, 반드시 배열을 원래 상태로 초기화 시켜줘야 한다는 것이다.



배열을 돌릴 때에는, 모든 값을 보존하면서 돌리는 것이 불가능 하다. 돌리는 순서, 방향에 따라서 반드시 모서리중 어느 한 값은 손실이 발생할 수 밖에 없는데, 그 값을 정해서 미리 담아두고, 마지막에 채워주면 된다.


본인은 가장 좌측 상단의 값을 기억해두고, 그 위치를 없어지는 값으로 정했다. 마지막에 그 값이 옮겨가야 할 곳에 넣어주면 된다.



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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include<iostream>
#include<limits.h>
struct Spin {
    int r, c, size;
}sp[8];
using namespace std;
 
int R, C, k, m[51][51],tmp[51][51], arr[8];
bool isused[8];
int Min = INT_MAX;
 
void spin(int val) {
    int rr = sp[val].r, cc = sp[val].c, size = sp[val].size;
    for (int l = 1; l <= size; l++) {
        int leftHigh = m[rr - l][cc - l]; //위쪽 변 넣을때 마지막에 넣어주기
        
        for (int row = rr - l; row <= rr + l-1; row++)  //왼쪽 변
            m[row][cc - l] = m[row+1][cc - l];
    
        for (int col = cc - l; col <= cc + l - 1; col++)  //아래쪽 변
            m[rr + l][col] = m[rr + l][col + 1];
        
 
        for (int row = rr + l; row >= rr - l + 1; row--)  //우측 
            m[row][cc + l] = m[row - 1][cc + l];
        
 
        for (int col = cc + l; col >= cc - l + 2; col--)  //상단
            m[rr - l][col] = m[rr - l][col - 1];
        
        m[rr - l][cc - l + 1= leftHigh; //기억해 놨던 맨 왼쪽 상단 값 넣어줌
    }
    
}
 
void calMin() {
    int inMin = INT_MAX;
    for (int i = 1; i <= R; i++) {
        int Sum = 0;
        for (int j = 1; j <= C; j++
            Sum += m[i][j];
        
        if (inMin > Sum) inMin = Sum;
    }
    if (inMin < Min) Min = inMin;
    
}
void init() {
    for (int i = 1; i <= R; i++)
        for (int j = 1; j <= C; j++)
            m[i][j] = tmp[i][j];
}
void backTracking(int num) {
    if (num == k) {
        for (int i = 0; i < k; i++)
            spin(arr[i]);
        calMin();
        
        init(); //배열 돌리기 이전으로 초기화
        return;
    }
    for (int i = 0; i < k; i++) {
        if (!isused[i]) {
            arr[num] = i;
            isused[i] = true;
            backTracking(num + 1);
            isused[i] = false;
        }
    }
}
int main(void) {
    cin >> R >> C >> k;
    for (int i = 1; i <= R; i++) {
        for (int j = 1; j <= C; j++) {
            cin >> m[i][j];
            tmp[i][j] = m[i][j];
        }
    }
 
    for (int i = 0; i < k; i++
        cin >> sp[i].r >> sp[i].c >> sp[i].size;
    
    backTracking(0);
    cout << Min;
    return 0;
}
cs


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

 

11053번: 가장 긴 증가하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.

www.acmicpc.net

 

가장 긴 감소하는 부분 수열의 반대 문제되겠다.

 

당시에는 몰랐는데 꽤 여러곳에 응용되는 전형적인 알고리즘인 것 같다.

 

문제에서 주어진 예시를 활용해서 아이디어를 좀 더 깔끔하게 정리해보자.

 

10 20 10 30 20 50

 

위와 같은 예시가 주어졌다.

 

먼저 10까지만 봤을 때는, 부분 수열의 길이는 1이다.

 

이제 20을 확인해보자. 초기에 20을 확인하면, 수열의 성분은 20하나이기때문에 길이는 1이다.

 

즉 d[]의 초기값은 모두 1이라고 할 수 있다.

 

이제 10과 비교해서 확인해보자. 10은 20보다 작기때문에 기본적으로 증가 수열의 조건을 만족한다.

 

또 한가지 확인해야 할 것은, 10에 20을 연결했을때, 기존에 20과 연결되어있는 다른 수열보다 길이가 길겠느냐 하는 것을 생각해 보는 것이다.

 

20까지만 확인한 경우, 이전에 나온 성분이 10밖에 없기 때문에 다소 모호하게 보일 수 있겠다.

 

일단 d[1]의 값은 2이다. (10과 20이 증가 수열을 이루기 때문에)

 

다음으로 10을 살펴보자. 초기에 10 자체로 수열을 이룬다고 볼 수 있기 때문에 앞서 언급한 것처럼 초기값은 1이다.

 

이제 가장 앞의 10과 비교해보자. 10은 10과 이어져서 증가 수열을 이룰 수 없다. 마찬가지로 20과도 이어질 수 없다. 따라서 d[2] = 1이 되겠다.

 

다음으로 30을 살펴보자. 30에 대해서 10을 먼저 비교해보면, 30은 10과 이어서 증가 수열이 될 수 있다. 따라서 10과 함께 증가 수열을 이룬다고 할 때, d[3] = 2가 되겠다.

 

20과 비교해보자. 20은 10과 연결되어서 증가 수열을 이룰 수 있다고 앞에서 확인했었다. 그렇다면 30을 연결하면? 

 

길이가 3이된다. 30은 현재 10과 연결해서 길이 2의 부분 증가 수열을 이루고 있었는데, 20과 연결된다면 길이가 증가할 수 있다. 따라서 20과 연결되어서 길이가 3이된다. d[2] = 3이 된다.

 

이런 흐름의 알고리즘을 활용하면 된다.

 

#include<iostream>
using namespace std;

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int n;
	cin >> n;
	int arr[1000];
	for (int i = 0; i < n; i++)
		cin >> arr[i];

	int d[1000];
	int Max = 0;
	for (int i = 0; i < n; i++) {
		d[i] = 1;
		for (int j = 0; j < i; j++) {
			if (arr[i] > arr[j] && d[i] < d[j] + 1)
				d[i]++;
		}
		if (Max < d[i]) Max = d[i];
	}
	cout << Max << '\n';

	return 0;
}

 

문제 링크

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

 

1926번: 그림

어떤 큰 도화지에 그림이 그려져 있을 때, 그 그림의 개수와, 그 그림 중 넓이가 가장 넓은 것의 넓이를 출력하여라. 단, 그림이라는 것은 1로 연결된 것을 한 그림이라고 정의하자. 가로나 세로로 연결된 것은 연결이 된 것이고 대각선으로 연결이 된 것은 떨어진 그림이다. 그림의 넓이란 그림에 포함된 1의 개수이다.

www.acmicpc.net

 

섬의 개수를 파악한다고 자주 기술했었는데, 간단하게 floodfill을 수행해주면 된다.

 

그림의 수를 파악하고, 그림의 넓이를 담아둘 때는 방문 처리 배열을 사용한다.

 

#include<iostream>
#include<queue>
using namespace std;

int map[500][500], dist[500][500];
int row, col;

queue<pair<int, int> > q;
int dr[4] = { 0, 0, 1, -1 };
int dc[4] = { 1, -1, 0, 0, };

int cnt = 0;
void bfs(pair<int, int> start) {
	cnt++; //섬개수 확인
	q.push(start);
	dist[start.first][start.second]++; 
	int di = 2; //위에서 시작점 방문하면 거리 1이니까, 다음으로 들어갈 거리는 2

	while (!q.empty()) {
		pair<int, int> cur = q.front();
		q.pop();

		for (int i = 0; i < 4; i++) {
			int nr = cur.first + dr[i];
			int nc = cur.second + dc[i];

			if (nr < 0 || nc < 0 || nr >= row || nc >= col || map[nr][nc] == 0 || dist[nr][nc] > 0)continue;

			q.push({ nr, nc });
			dist[nr][nc] = di;
			di++;
			
		}
	}
}

int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> row >> col;
	for(int i = 0 ; i < row ; i++)
		for (int j = 0; j < col; j++) {
			cin >> map[i][j];
		}

	for (int i = 0; i < row; i++)
		for (int j = 0; j < col; j++) {
			if (map[i][j] == 1 && dist[i][j] == 0)
				bfs({ i, j });
		}
	//방문처리 배열에 카운트를 해뒀기때문에 그 안에서 최댓값을 구하면 된다.
	int Max = -1;
	for (int i = 0; i < row; i++) {
		for (int j = 0; j < col; j++) {
			if (dist[i][j] > Max)
				Max = dist[i][j];
		}
	}
	cout << cnt << '\n' << Max << '\n';
	return 0;
}


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



좌표 평면위의 점의 최장 거리를 이루는 두 점은 하나의 볼록 껍질 위에 존재한다는 것을 이용해서 푼다.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
struct P{
    ll x, y;
    P operator- (P a) { 
        return { x - a.x, y - a.y };
    }
}b[200001];
vector<P> v;
ll ccw(P p1, P p2) {
    ll ret = p1.x*p2.y - p2.x*p1.y;
    if (ret < 0return -1;
    else if (ret > 0return 1;
    else return 0;
}
ll ccw(P c, P a, P b) {
    return ccw(a - c, b - c);
}
ll sqdis(P p1, P p2) {
    return (p1.x - p2.x) *(p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
bool cmp(P p1, P p2) {
    ll ret = ccw(b[0], p1, p2);
    if (ret > 0return true;
    else if (ret < 0return false;
    else {
        if (sqdis(b[0], p1) < sqdis(b[0], p2)) return true;
        else return false;
    }
}
int main(void) {
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        int Min = 111111111, idx = 0//y값 최소 다음 x값 최소
        for (int i = 0; i < n; i++) {
            cin >> b[i].x >> b[i].y;
            if (b[i].y < Min) {
                Min = b[i].y;
                idx = i;
            }
            else if (b[i].y == Min) {
                if (b[i].x < b[idx].x) idx = i;
            }
          }
        swap(b[0], b[idx]);
        sort(b + 1, b + n, cmp);
        
        //graham scan
        for (int i = 0; i < n; i++) {
            while (v.size() >= 2 && ccw(v[v.size() - 2], v[v.size() - 1], b[i]) <= 0) {
                v.pop_back(); 
            }
            v.push_back(b[i]);
        }
        v.push_back(b[0]); //마지막에 첫점 연결
 
        ll ans = -1;
        int j = 1, st, en;
        for (int i = 0; i < v.size()-1; i++) {
            while (i != j && ccw(v[i + 1- v[i], v[j + 1- v[j]) > 0) {
                j++;
                if (j >= v.size() - 1) j = 0;
            }
            ll dist = sqdis(v[i], v[j]); //ccw가 양수가 아니게 되는 순간마다 거리 측정
            if (ans < dist) {
                st = i;
                en = j;
                ans = dist;
            }
        }
        printf("%lld %lld %lld %lld\n", v[st].x, v[st].y, v[en].x, v[en].y);
        v.clear();
    }
    return 0;
}
cs


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


모든 노드의 연결 관계를 파악해야한다.


n 이 500이므로 플로이드 와샬을 사용할 수 있고, 모든 정점으로부터 다른 모든 정점까지의 비용을 파악할 수 있다.


비용은 1로 두고, 갈 수 있는지 없는지만 파악하면 된다.


주의할 사항은, degree를 계산할 때, 자신에서 자신으로 가는 것은 카운트하지 않아야 한다는 것이다.


자기 자신으로의 경로 비용 초기화를 어떻게 했는지에 따라 잘 처리해주면 되겠다.



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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<iostream>
#include<algorithm>
#define INF 100000000
using namespace std;
int map[501][501], m, n, degree[501];
void FW() {
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
            }
        }
    }
 
    // 노드 i까지 갈 수 있는 노드의 수 + 노드 i에서 갈 수 있는 노드수
    // 이게 n-1이면 됨. degree 계산
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (map[i][j] != INF && i != j) {
                degree[i]++;
                degree[j]++;
            }
        }
    }
}
int main(void) {
    cin >> n >>m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            map[i][j] = i==j ? 0 : INF;
        }
 
    for (int i = 0; i < m; i++) {
        int src, dst;
        cin >> src >> dst;
        map[src][dst] = 1;
    }
    FW();
    int res = 0;
    for (int i = 1; i <= n; i++)
        if (degree[i] == n - 1) res++;
    cout << res;
    return 0;
}
 
//n이 500 -> 행렬에 다 넣어도 됨
//비용 1로두고 플와 돌려서 모든 간선 연결 및 비용 파악
 
cs


'알고리즘 문제 풀이 > 백준 온라인 저지' 카테고리의 다른 글

백준 1926번 그림 (C++)  (0) 2019.08.19
백준 10254 고속도로 C++  (0) 2019.08.17
백준 1806 부분합 C++  (0) 2019.08.16
백준 11404 플로이드 C++  (0) 2019.08.16
백준 11657 타임머신 C++  (0) 2019.08.16

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



투포인터를 활용해주면 된다.


길이를 언제 갱신하고, 무한루프를 어느 위치에서 종료할 것인지만 명확히 해준다면 무리없이 풀리는 문제이다.


현재까지 더한 구간합이, 넘겨야할 합보다 크다면 일단 그 시점의 길이가 최소 길이인지 비교해서 갱신해준다.


이후 왼쪽 인덱스 포인터를 증가시키고 길이를 감소시키고, 변화된 상태가 조건을 만족하는지 확인해주고 이런 흐름이다.


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
31
32
33
34
35
36
37
#include<iostream>
 
using namespace std;
typedef long long ll;
const int INF = 1000000;
int main(void) {
    ll arr[100001];
    double s;
    int n;
    cin >> n >> s;
    for (int i = 0; i < n; i++)
        cin >> arr[i];
    
    int l = 0, h = 0, len = 0, Min = INF;
    ll Sum = 0;
    while (1) {
        if (Sum < s) {
            if (h > n - 1break//h가 n인데, 쿼리를 실행하게 하면 안된다
            Sum += arr[h];
            h++;
            len++;
        }
        else {
            if (len < Min) Min = len;
            
            Sum -= arr[l];
            l++
            len--;
        }
    }
    if (Min != INF)
        cout << Min << '\n';
    else
        cout << 0 << '\n';
    
    return 0;
}
cs


'알고리즘 문제 풀이 > 백준 온라인 저지' 카테고리의 다른 글

백준 10254 고속도로 C++  (0) 2019.08.17
백준 2458 키 순서 C++  (0) 2019.08.16
백준 11404 플로이드 C++  (0) 2019.08.16
백준 11657 타임머신 C++  (0) 2019.08.16
백준 1753 최단경로 C++  (0) 2019.08.15

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


상관없는지 모르겠으나 원래는 kij순으로 루프 돌아야한다


문제 이름에서부터 플로이드 와샬 알고리즘을 사용해야 한다는 것을 암시하고 있는 문제이다.


주의할 것은, 이전까지 INF 값으로 limits.h 헤더에 있는 INT_MAX를 사용했는데, 이 값에 어떤 값이 더해지는 연산을 하게되면 오버플로우가 발생한다.


다익스트라, 벨만포드에서는 괜찮았지만 플로이드에서 이런 일이 생기니, 그냥 속편하게 내가 INF를 지정해서 써야겠다.


INF는 항상 (간선 가중치의 최댓값 ) * (정점 개수 - 1 ) 보다 크게 잡아줘야 한다.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<iostream>
#include<algorithm>
#include<limits.h>
using namespace std;
int n, m;
int dis[101][101];
const int MAX = 1000000000//INF는 항상 (간선 가중치의 최댓값) * (정점 개수 - 1) 보다 큰 값
void FW() {
    for (int k = 1; k <= n; k++
        for (int j = 1; j <= n; j++
            for(int i = 1; i <= n; i++
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
 
int main(void) {
    //ios::sync_with_stdio(false);
    cin.tie(0);
        
    cin >> n >> m;
    for (int i = 1; i <= n; i++
        for (int j = 1; j <= n; j++
            dis[i][j] = i == j ? 0 : MAX;
        
    for (int i = 0; i < m; i++) {
        int src, dst, cost;
        cin >> src >> dst >> cost;
        dis[src][dst] = min(dis[src][dst], cost);
    }
 
    FW();
 
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (dis[i][j] == MAX) dis[i][j] = 0;
             cout << dis[i][j] << ' ';
        }
        cout << '\n';
    }
 
    return 0;
}
 
 
cs


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



벨만 포드 알고리즘을 사용하는 문제는 음수 가중치를 가지고 무언가를 하는 문제들인데, 거리 / 비용을 음수로 주기는 표현이 애매하기 때문에 이 문제에서처럼 시간을 가지고 문제를 만드는 것 같다. 웜홀, 시간 여행 등의 주제로 나오는 것 같다.


초기에 간선들의 정보를 받아주고, 다익스트라와 동일하게 모든 정점으로 가는 비용을 무한대로 초기화 한다.


그리고 n-1번에 거쳐서, 모든 정점들의 모든 간선들을 탐색해주고, 마지막 한 번은 음수 사이클 검사용으로 탐색해준다.


마지막 1번의 검색에서, 즉 가장 바깥 루프의 n번째 탐색시에, 경로 / 비용의 갱신이 발생한다면, 이 그래프는 음수 사이클을 포함하고 있다는 의미이다.


그렇지 않으면, 당연히 n개의 정점을 최소비용으로 이동하는 데에 n-1개의 간선이면 충분하기 때문이다.


n-1개 이상 간선을 사용한다는 것은? 어딘가에 음수 사이클이 있기 때문에 계속 그곳을 지나가게끔 갱신이 발생되고 있다는 의미이다.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<iostream>
#include<limits.h>
#include<utility>
#include<vector>
using namespace std;
 
typedef pair<intint> pii;
vector<pii> v[501]; //비용, 목적지
int n, m, dis[501];
bool hasNegativeCycle = false;
void bellmanFord(int st) {
    dis[st] = 0;
    
    for (int t = 0; t < n; t++) { //n-1번 수행하고 +1번은 음수 사이클 확인용
        for (int i = 1; i <= n; i++) { //모든 정점의 간선을 확인하는 것을
            for (int j = 0; j < v[i].size(); j++) {
                int moveCost = v[i][j].first;
                int dst = v[i][j].second;
                if (dis[i] != INT_MAX && dis[dst] > dis[i] + moveCost) {
                    dis[dst] = dis[i] + moveCost;
                    if (t == n-1) hasNegativeCycle = true;
                }
            }
        }
    }
}
int main(void) {
    //ios::sync_with_stdio(false);
    cin.tie(0);
 
    //도시 n개, 엣지 m개
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int from, to, cost;
        cin >> from >> to >> cost;
        v[from].push_back({ cost, to });
    }
    
    //음수사이클 -> -1, 아니면 1번부터 각 노드까지 거리
    for (int i = 1; i <= n; i++)
        dis[i] = INT_MAX;
    bellmanFord(1);
    if (hasNegativeCycle) cout << -1 << '\n';
    else {
        for (int i = 2; i <= n; i++) {
            if (dis[i] != INT_MAX)
                cout << dis[i] << '\n';
            else
                cout << -1 << '\n';
        }
    }
    return 0;
}
 
cs


'알고리즘 문제 풀이 > 백준 온라인 저지' 카테고리의 다른 글

백준 1806 부분합 C++  (0) 2019.08.16
백준 11404 플로이드 C++  (0) 2019.08.16
백준 1753 최단경로 C++  (0) 2019.08.15
백준 1916 최소비용 구하기 C++  (0) 2019.08.15
백준 11438 LCA2 C++  (0) 2019.08.15

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


다익스트라 알고리즘을 구현해주면 된다.


방문했던 노드를 다시 방문하지 않도록 해주어야 TLE를 피할 수 있을 것이다.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<functional>
#include<limits.h>
using namespace std;
int n, m, dist[20001];
 
typedef pair<intint> pii;
bool vis[20001];
vector<pii> e[20001]; //비용, 목적지
priority_queue<pii, vector<pii>, greater<pii> > pq;
void dijkstra(int st) {
    dist[st] = 0;
    
    pq.push({ dist[st], st });
 
    while (!pq.empty()) {
        int here = pq.top().second;
        vis[here] = true;
        
        pq.pop();
        for (int i = 0; i < e[here].size(); i++) {
            int there = e[here][i].second;
            if (vis[there]) continue;
            int moveCost = e[here][i].first;
            if (dist[there] > dist[here] + moveCost) {
                dist[there] = dist[here] + moveCost;
                pq.push({ dist[there], there });
                
            }
        }
    }
}
int main() {
    cin >> n >> m;
    int src;
    cin >> src;
    while (m--) {
        int from, to, cost;
        cin >> from >> to >> cost;
        e[from].push_back({ cost, to });
    }
    for (int i = 1; i <= n; i++)
        dist[i] = INT_MAX;
    
 
    dijkstra(src);
    
    for (int i = 1; i <= n; i++) {
        if (dist[i] != INT_MAX) cout << dist[i] << '\n';
        else cout << "INF" << '\n';
    }
    return 0;
}
cs


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


가중치가 있는 그래프의 최소 비용 / 최단 경로를 구하는 문제이다.


가중치들이 모두 양수이기 때문에 다익스트라를 이용한다.



먼저 시작점으로부터 i번 노드까지 가는 총 비용을 의미하는 dist[i]를 무한대로 초기화한다.



알고리즘이 시작되면, 시작점으로부터 시작점까지의 비용은 0인 것이 자명하기 때문에 dist[시작점] = 0으로 바꿔준다.


그리고 시작점으로부터의 거리가 가장 낮은 것부터 뽑을 것이기 때문에 min heap을 사용한다.



이 때, pair에 특정 노드번호와, 그 노드까지 가는 비용을 함께 관리할 것이다. 주의할 점은, pair의 대소 비교는 first부터 일어나기 때문에 반드시 비용을 first에 넣어줄 수 있도록 한다.



이후로는 현재노드까지 오는 비용 + 이동할 수 있는 노드로의 이동 비용 < 다음 노드까지 가는 총비용


위의 경우에 다음 노드까지 가는 총 비용을 갱신해준다.


갱신되는 경우에, heap에 갱신되는 지점을 넣어주도록 하자.



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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<functional>
#include<limits.h>
using namespace std;
int n, m, dist[20001];
 
typedef pair<intint> pii;
bool vis[20001];
vector<pii> e[20001]; //비용, 목적지
priority_queue<pii, vector<pii>, greater<pii> > pq;
void dijkstra(int st) {
    dist[st] = 0;
    
    pq.push({ dist[st], st });
 
    while (!pq.empty()) {
        int here = pq.top().second;
        vis[here] = true;
        
        pq.pop();
        for (int i = 0; i < e[here].size(); i++) {
            int there = e[here][i].second;
            if (vis[there]) continue;
            int moveCost = e[here][i].first;
            if (dist[there] > dist[here] + moveCost) {
                dist[there] = dist[here] + moveCost;
                pq.push({ dist[there], there });
                
            }
        }
    }
}
int main() {
    cin >> n >> m;
 
    while (m--) {
        int from, to, cost;
        cin >> from >> to >> cost;
        e[from].push_back({ cost, to });
    }
    for (int i = 1; i <= n; i++)
        dist[i] = INT_MAX;
    
    int src, dst;
    cin >> src >> dst;
    dijkstra(src);
    
    cout << dist[dst];
    return 0;
}
cs


+ Recent posts