반응형

문제 링크: https://www.acmicpc.net/problem/1922

 

1922번: 네트워크 연결

이 경우에 1-3, 2-3, 3-4, 4-5, 4-6을 연결하면 주어진 output이 나오게 된다.

www.acmicpc.net

<문제 풀이> 최소 스패닝 트리, 크루스칼 알고리즘

 

크루스칼 알고리즘을 사용해서 최소 비용으로 모든 노드를 연결하면 됩니다.

 

<C++소스코드>

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
#include <iostream>
#include<algorithm>
using namespace std;
 
int n;
int arr[50];
int visited[50]; //이미 본 인덱스는 다시 보지 않음
 
//k보다 크거나 같은 범위에서 target인 수가 존재하는지 판별
//return index
int findX(int k, int target) {
    for (int i = k; i < n; i++) {
        if (visited[i])continue;
        if (arr[i] == target) return i;
    }
    return -1;
}
 
//k보다 크거나 같은 범위에서 target보다 크거나 같은 수가 존재하는지 판별
//return index
int findY(int k, int target) {    
    for (int i = k; i < n; i++) {
        if (visited[i])continue;
        if (arr[i] >= target) return i;
    }
    return -1;
}
 
int main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }
 
    sort(arr, arr + n); // 오름차순 정렬
 
    for (int i = 0; i < n; i++) {
        if (visited[i]) continue;
 
        int x = findX(i, arr[i] + 1); // A[i] + 1인 수가 존재하는지 판별 
        int y = findY(i, arr[i] + 2); // A[i] + 2보다 크거나 같은 수가 존재하는지 판별
 
        if (x != -1 && y != -1) { // 둘 다 존재하면
            for (int j = 0; j < n; j++) { // A[i]를 모두 출력하고
                if (arr[i] == arr[j] && !visited[j]) {
                    cout << arr[j] << ' ';
                    visited[j] = true;
                }
            }
            //A[i] + 2보다 크거나 같은 최초의 수를 출력한다 ex) 1233 -> 13 출력 후 다음 A[i]는 2부터 시작
            cout << arr[y] << ' ';
            visited[y] = true;
        }
        else if(x != -1 && y == -1) { // A[i] + 1인 수를 찾았는데 A[i] + 2보다 크거나 같은 수가 존재하지 않으면 ex) 111122222
            for (int j = 0; j < n; j++) { //A[i] + 1인 수를 모두 출력하고
                if (arr[x] == arr[j] && !visited[j]) {
                    cout << arr[j] << ' ';
                    visited[j] = true;
                }
            }
            // A[i]를 모두 출력한다. ex) 222221111 출력
            for (int j = 0; j < n; j++) {
                if (arr[i] == arr[j] && !visited[j]) {
                    cout << arr[j] << ' ';
                    visited[j] = true;
                }
            }
 
        }
        else { // A[i] + 1인 수를 못찾았을 때 
            cout << arr[i] << ' '// A[i]를 출력한다. ex) 1334 A[i] == 1 일 때 1 출력 후 다음 A[i]는 3이 된다.
            visited[i] = true;
        }
        
 
    }
}
cs

 

반응형
반응형

문제 링크: https://www.acmicpc.net/problem/4485

 

4485번: 녹색 옷 입은 애가 젤다지?

젤다의 전설 게임에서 화폐의 단위는 루피(rupee)다. 그런데 간혹 '도둑루피'라 불리는 검정색 루피도 존재하는데, 이걸 획득하면 오히려 소지한 루피가 감소하게 된다! 젤다의 전설 시리즈의 주

www.acmicpc.net

<문제 풀이> 다익스트라 알고리즘

 

다익스트라 알고리즘으로 출발점에서 도착점까지 최단 경로를 구하면 됩니다.

 

<C++소스코드>

 
#include<iostream>
#include<queue>
#include<functional>
#include<cstring>
#include<utility>
#include<tuple>
using namespace std;

const int MAX_N = 125;
const int dx[4] = { 0, 0, 1, -1 };
const int dy[4] = { 1, -1, 0, 0 };

int board[MAX_N][MAX_N];
int d[MAX_N][MAX_N];
int n;

bool OOB(int x, int y) {
    return (x < 0 || y < 0 || x >= n || y >= n);
}

int dijkstra(int sx, int sy) {
    memset(d, 0x3f, sizeof(d));
    priority_queue<tuple<int, int, int>, vector<tuple<int, int, int> >, greater<tuple<int, int, int> > > pq;
    d[sx][sy] = board[sx][sy];
    pq.push({ d[sx][sy], sx, sy });
    while (!pq.empty()) {
        int cx, cy, cur_dist; tie(cur_dist, cx, cy) = pq.top(); pq.pop();
        if (d[cx][cy] != cur_dist) continue;

        for (int dir = 0; dir < 4; dir++) {
            int nx = cx + dx[dir];
            int ny = cy + dy[dir];
            if (OOB(nx, ny)) continue;
            int nxt_dist = cur_dist + board[nx][ny];
            if (nxt_dist < d[nx][ny]) {
                d[nx][ny] = nxt_dist;
                pq.push({nxt_dist, nx, ny });
            }
        }
    }
    return d[n - 1][n - 1];
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    int test_case = 0;
    while (true) {
        test_case++;
        cin >> n;
        if (n == 0) break;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                cin >> board[i][j];
            }
        }
        cout << "Problem " << test_case << ": " << dijkstra(0, 0) << '\n';
    }


    return 0;
}
반응형
반응형

문제 링크: https://www.acmicpc.net/problem/5972

 

5972번: 택배 배송

농부 현서는 농부 찬홍이에게 택배를 배달해줘야 합니다. 그리고 지금, 갈 준비를 하고 있습니다. 평화롭게 가려면 가는 길에 만나는 모든 소들에게 맛있는 여물을 줘야 합니다. 물론 현서는

www.acmicpc.net

<문제 풀이> 다익스트라 알고리즘

 

다익스트라 알고리즘을 사용해서 출발지부터 도착지까지의 최단거리를 구하면 됩니다.

 

 

<C++소스코드>

 
#include<iostream>
#include<vector>
#include<utility>
#include<cstring>
#include<queue>
#include<functional>
using namespace std;

const int MAX_N = 50000;

int N, M;
vector<pair<int, int> > adj[MAX_N + 1];
int d[MAX_N + 1];
int dijkstra(int start, int end) {
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq;
    memset(d, 0x3f, sizeof(d));

    d[start] = 0;
    pq.push({ d[start], start });
    while (!pq.empty()) {
        auto cur = pq.top(); pq.pop();
        int dist = cur.first;
        int curIdx = cur.second;
        if (d[curIdx] != dist) continue;
        for (auto& nxt : adj[curIdx]) {
            int cost = nxt.first;
            int nIdx = nxt.second;
            if (d[curIdx] + cost < d[nIdx]) {
                d[nIdx] = d[curIdx] + cost;
                pq.push({ d[nIdx], nIdx });
            }
        }
    }
    return d[end];
}

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

    cin >> N >> M;
    for (int i = 0; i < M; i++) {
        int u, v, w; cin >> u >> v >> w;
        adj[u].push_back({ w, v });
        adj[v].push_back({ w, u });
    }

    cout << dijkstra(1, N);


    return 0;
}
반응형
반응형

문제 링크: https://www.acmicpc.net/problem/14442

 

14442번: 벽 부수고 이동하기 2

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

www.acmicpc.net

<문제 풀이> BFS 알고리즘

 

BFS를 사용하여 최단거리를 찾을 때, 현재까지 몇 개의 벽을 부쉈는지를 체크하기 위해서 3차원 visited 배열을 다음과 같이 선언합니다.

 

visited[N][M][K] : (N,M) 좌표를 K개의 벽을 부수고 방문했을 때의 최단 거리

 

BFS의 큐에는 (좌표, 현재까지 몇 개의 벽을 부쉈는지)에 대한 정보를 담고,  다음과 같은 조건을 만족할 때 큐에 삽입합니다.

 

1. 다음 좌표가 벽일 때

벽을 부술 수 있는 횟수(K)가 남아있고 && 현재 좌표에서 벽을 부수고 다음 좌표를 방문했을 때 거리가 더 짧은 경우

 

2. 다음 좌표가 벽이 아닐 때

현재 좌표에서 다음 좌표를 방문했을 때 거리가 더 짧은 경우

 

 

 

<C++소스코드>

 
#include<iostream>
#include<cstring>
#include<queue>
#include<utility>
#include<tuple>
#include<algorithm>
using namespace std;

const int MAX_N = 1000;
const int MAX_M = 1000;
const int MAX_K = 10;
const int dx[4] = { 0, 0, 1, -1 };
const int dy[4] = { 1, -1, 0, 0 };
const int INF = 0x3f3f3f3f;
bool board[MAX_N + 1][MAX_M + 1];
int dist[MAX_N+1][MAX_M+1][MAX_K + 1];

int N, M, K;

bool OOB(int x, int y) {
    return (x < 1 || y < 1 || x > N || y > M);
}

int bfs() {
    memset(dist, 0x3f, sizeof(dist));
    queue<tuple<int, int, int> > Q;
    Q.push({ 1, 1, 0});
    dist[1][1][0] = 1;
    
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        int cx, cy, cnt; tie(cx, cy, cnt) = cur;
        for (int dir = 0; dir < 4; dir++) {
            int nx = cx + dx[dir];
            int ny = cy + dy[dir];
            if (OOB(nx, ny)) continue;

            if (board[nx][ny] == 1) {
                //벽 부수기 O
                if (cnt < K &&  dist[cx][cy][cnt] + 1 < dist[nx][ny][cnt + 1]) {
                    Q.push({ nx,ny, cnt + 1 });
                    dist[nx][ny][cnt + 1] = dist[cx][cy][cnt] + 1;
                }   
            }
            else {
                if (dist[cx][cy][cnt] + 1 < dist[nx][ny][cnt]) {
                    Q.push({ nx, ny, cnt });
                    dist[nx][ny][cnt] = dist[cx][cy][cnt] + 1;
                }
            }
        }
    }

    int ans = INF;
    
    for (int i = 0; i <= K; i++) {
        ans = min(ans, dist[N][M][i]);
    }
    if (ans >= INF) return -1;
    else return ans;
}

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

    cin >> N >> M >> K;
    
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            char c; cin >> c;
            board[i][j] = c - '0';
        }
    }

    cout << bfs();
    
    return 0;
}
반응형
반응형

문제 링크: https://www.acmicpc.net/problem/5719

 

5719번: 거의 최단 경로

입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스의 첫째 줄에는 장소의 수 N (2 ≤ N ≤ 500)과 도로의 수 M (1 ≤ M ≤ 104)가 주어진다. 장소는 0부터 N-1번까지 번호가 매겨져 있

www.acmicpc.net

<문제 풀이> 다익스트라 알고리즘

 

다익스트라로 최단 거리를 갱신하고, 가능한 모든 최단 경로 삭제 후 다시 다익스트라로 최단거리를 갱신하면 됩니다.

 

최단 경로를 삭제하기 위해 각 정점에 도달하기 전의 정점을 기록할 수 있는 자료구조가 필요합니다. 이때 가능한 최단거리가 여러 개 있을 수 있으므로 vector<int> 타입의 배열을 사용하여 이전 정점들을 저장해야 합니다.

 

제거할 때는 최단 경로 배열을 가지고 도착점에서 출발점까지 BFS를 호출하면서 간선을 제거해 줍니다.

간선 제거는 2차원 배열로 표현할 수 있습니다.

removed[i][j] = true; // i -> j 간선 제거

 

 

<C++소스코드>

 
#include<iostream>
#include<utility>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;

vector<pair<int, int> >adj[500];
vector<int> pre[500];
bool removed[500][500];

const int INF = 0x3f3f3f3f;

int d[500];

void init() {
    for (int i = 0; i < 500; i++) {
        adj[i] = {};
        for (int j = 0; j < 500; j++) {
            removed[i][j] = false;
        }
    }
}

void EraseEdge(int start, int end) {
    int cur = end;
    queue<int> Q;
    Q.push(cur);
    while (!Q.empty()) {
        auto cur = Q.front(); Q.pop();
        for (auto u : pre[cur]) {
            if (removed[u][cur]) continue;
            removed[u][cur] = true;
            Q.push(u);
        }
    }
}

int dijkstra(int start, int end) {
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq;
    for (int i = 0; i < 500; i++) {
        pre[i] = {};
    }
    memset(d, 0x3f, sizeof(d));

    d[start] = 0;
    pq.push({ d[start], start });

    while (!pq.empty()) {
        auto cur = pq.top(); pq.pop();
        int dist = cur.first;
        int curIdx = cur.second;
        if (d[curIdx] != dist) continue;
        for (auto& nxt : adj[curIdx]) {
            int cost = nxt.first;
            int nIdx = nxt.second;
            
            if (removed[curIdx][nIdx]) continue;

            if (d[curIdx] + cost == d[nIdx]) {
                pre[nIdx].push_back(curIdx);
            }
            if (d[curIdx] + cost < d[nIdx]) {
                d[nIdx] = d[curIdx] + cost;
                pre[nIdx].clear();
                pre[nIdx].push_back(curIdx);
                pq.push({ d[nIdx], nIdx });
            }
        }
    }
    if (d[end] >= INF) return -1;
    return d[end];
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    while (true) {
        init();
        vector<int> ans;
        int N, M; cin >> N >> M;
        if (N == 0 && M == 0) break;

        int S, D; cin >> S >> D;
        for (int i = 0; i < M; i++) {
            int u, v, w; cin >> u >> v >> w;
            adj[u].push_back({ w, v });
        }
        dijkstra(S, D);
        EraseEdge(S, D);
        cout<<dijkstra(S, D)<<'\n';
   
    }
    
    return 0;
}
반응형
반응형

문제 링크: https://www.acmicpc.net/problem/1774

 

1774번: 우주신과의 교감

(1,1) (3,1) (2,3) (4,3) 이렇게 우주신들과 황선자씨의 좌표가 주어졌고 1번하고 4번이 연결되어 있다. 그렇다면 1번하고 2번을 잇는 통로를 만들고 3번하고 4번을 잇는 통로를 만들면 신들과 선자씨끼

www.acmicpc.net

<문제 풀이> 최소 스패닝 트리, 크루스칼 알고리즘

 

모든 서로 다른 두 정점 사이에 거리를 구해서 간선에 추가하고 크루스칼 알고리즘을 이용하여 최소 스패닝 트리를 찾으면 됩니다.

 

[주의할 점]

1. 이미 연결된 통로를 입력받을 때, 중복된 간선이 들어올 수 있습니다.

 

예를 들어, 1-2와 2-1은 동일한 간선을 나타냅니다. 이 경우를 고려하지 않으면 현재까지 최소 스패닝 트리에 추가된 간선의 수를 계산할 때 문제가 생길 수 있습니다.

 

2. 좌표 값의 최댓값이 10^6이므로, 거리를 계산할 때 오버플로우를 방지하기 위해 long long 자료형을 사용해야 합니다.

 

<C++소스코드>

 
#include<iostream>
#include<utility>
#include<algorithm>
#include<vector>
#include<tuple>
#include<cmath>
using namespace std;

typedef long long ll;

int n, m;
pair<ll, ll> arr[1001];
int parents[1001];
vector<tuple<double, ll, ll> > edge;

int Find(int x) {
    if (parents[x] == x) return x;
    return parents[x] = Find(parents[x]);
}

void Union(int x, int y) {
    int xParents = Find(x);
    int yParents = Find(y);
    if (xParents < yParents) parents[xParents] = yParents;
    else parents[yParents] = xParents;
}


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

    cin >> n >> m;
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        parents[i] = i;
    }
    for (int i = 1; i <= n; i++) {
        int x, y; cin >> x >> y;
        arr[i] = { x, y };
    }
    for (int i = 0; i < m; i++) {
        int u, v; cin >> u >> v;
        if (Find(u) == Find(v)) continue;
        cnt++;
        Union(u, v);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            if (Find(i) == Find(j)) continue;
            double dist = sqrt((arr[i].first - arr[j].first) * (arr[i].first - arr[j].first) + (arr[i].second - arr[j].second) * (arr[i].second - arr[j].second));
            edge.push_back({ dist, i, j });
        }
    }
    sort(edge.begin(), edge.end());
   
    double ans  = 0;
    for (auto& e : edge) {
        double dist;
        int u, v;
        tie(dist, u, v) = e;
        if (Find(u) == Find(v))continue;
        Union(u, v);
        cnt++;
        ans += dist;
        if (cnt == n - 1) break;
    }
    cout << fixed;
    cout.precision(2);
    
    cout << ans;

    return 0;
}
반응형
반응형

문제 링크: https://www.acmicpc.net/problem/2056

 

2056번: 작업

수행해야 할 작업 N개 (3 ≤ N ≤ 10000)가 있다. 각각의 작업마다 걸리는 시간(1 ≤ 시간 ≤ 100)이 정수로 주어진다. 몇몇 작업들 사이에는 선행 관계라는 게 있어서, 어떤 작업을 수행하기 위해

www.acmicpc.net

 

<문제 풀이> 다이나믹 프로그래밍(DP), 위상정렬 알고리즘

 

작업에는 순서가 있으므로 위상정렬을 사용해야 합니다. 또한, 모든 작업을 완료하기 위한 최소 시간을 구하기 위해 DP를 활용해야 합니다.

DP의 정의는 아래와 같습니다:

 

DP[i] : i번째 작업이 완료되는 데 필요한 최소 시간

 

위상 정렬을 수행하며 현재 작업에 연결된 다음 작업들의 최소 완료 시간을 갱신해 나갑니다. 현재 작업을'cur', 그에 연결된 다음 작업을 'next'라고 할 때, 'next'작업의 최소 완료 시간은 아래와 같이 계산합니다:

dp[next] = max(dp[next], dp[cur] + t[next]);

 

여기서 max함수를 사용하는 이유는 다음 작업에 대한 선행 작업들 중에서 최소 완료 시간이 가장 긴 작업이 그 작업의 완료 시간에 영향을 주기 때문입니다.

 

예를 들어, A 작업이 5분, C 작업이 3분이 걸린다고 할 때, B 작업을 시작하기 위해선 A작업이 완료되어야 합니다.

 

A(5분) -> B

B(3분) -> B

 

<C++소스코드>

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

vector<int> adj[10001];
int indegree[10001];
int t[10001];
int dp[10001];
int main(void) {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	
	int n; cin >> n;
	for (int u = 1; u <= n; u++) {
		cin >> t[u];
		int m; cin >> m;
		while (m--) {
			int v; cin >> v;
			adj[v].push_back(u);
			indegree[u]++;
		}
	}
	queue<int> Q;
	for (int u = 1; u <= n; u++){
		if (indegree[u] == 0) {
			Q.push(u);
			dp[u] = t[u];
		}
	}
	while (!Q.empty()) {
		auto cur = Q.front(); Q.pop();
		for (auto next : adj[cur]) {
			indegree[next]--;		
			dp[next] = max(dp[next], dp[cur] + t[next]);
			if (indegree[next] == 0) {
				Q.push(next);
			}
		}
	}
	cout << *max_element(dp + 1, dp + 1 + n);
	return 0;
}
반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 5719번] 거의 최단 경로  (0) 2023.09.18
[백준 1774번] 우주신과의 교감  (0) 2023.09.10
[백준 2283] 구간 자르기  (0) 2023.08.30
[백준 17521번] Byte Coin  (0) 2023.04.24
[백준 1439번] 뒤집기  (0) 2023.04.23
반응형

문제 링크: https://www.acmicpc.net/problem/2283

 

2283번: 구간 자르기

1번째 줄에 정수 N, K(1 ≤ N ≤ 1,000, 1 ≤ K ≤ 1,000,000,000)가 주어진다. 2~N+1번째 줄에 각 구간의 왼쪽 끝점과 오른쪽 끝점의 위치가 주어진다. 양 끝점의 위치는 0 이상 1,000,000 이하의 정수이다.

www.acmicpc.net

<문제 풀이> 투포인터, 누적합 알고리즘

 

먼저 모든 구간을 살펴봐야 하고 각 구간에 존재하는 막대기의 총길이가 K가 되도록 하는 조건이 있기 때문에 이 문제는 투포인터와 누적합을 사용해서 해결할 수 있습니다.

 

원래 모든 구간을 살펴보기 위해선 O(구간의길이^2)의 시간복잡도가 걸리지만, 각 구간에 존재하는 막대기의 총길이가 K가 되도록 하는 조건은 투포인터 문제로 변환할 수 있어서 O(구간의 길이)의 시간복잡도만 걸리게 됩니다.

 

1. 구간에 존재하는 막대기의 총 길이를 O(1)에 구하기 위해서 누적합을 사용합니다.

먼저 막대기를 표현하는 방법을 생각해봐야 하는데 입력으로 주어진 막대기의 왼쪽 좌표, 오른쪽 좌표 그리고 1차원 배열을 이용하면 막대기를 쉽게 표현할 수 있습니다.

 

예를 들어

[0, 3]인 막대기 한 개를 표현하면 아래와 같습니다.

bar[0] = 1, bar[3] = - 1

 

[0, 3]인 막대기를 0부터 3까지 순회하면서 현재 좌표의 배열값과 이전 배열의 값을 누적하면 각 좌표에 존재하는 막대기의 개수를 구할 수 있습니다.

idx 0 1 2 3 

val 1 1 1 0

 

마찬가지로,  [0, 3] 인 막대기, [0, 8]인 막대기 두 개를 표현하면 아래와 같습니다.

bar[0] = 2, bar[3] = -1, bar[8] = -1;

 

누적합을 구하면

idx 0 1 2 3 4 5 6 7 8 

val 2 2 2 1 1 1 1 1 0

 

즉 입력으로 주어진 막대기의 좌표를 가지고 bar[left]++, bar[right]--을 하면 막대기를 표현할 수 있습니다.  또한 배열을 순회하면서 누적합을 구하면 각 좌표에 해당하는 막대기의 개수를 구할 수 있습니다.

 

추가적으로 bar[i]는 [i - 1, i] 구간에 존재하는 막대기의 총길이와 같습니다.

 

2. 누적합을 가지고 투포인터로 모든 구간을 살펴보면서 구간의 길이의 총합이 K가 되는 구간을 구한다.

 

이제 투포인터 기본 문제랑 똑같습니다. left =0, right =0부터 시작하면서 구간을 점점 키워나가면 되는데, 이때 right를 증가시켰는데 K를 넘어가면 더 이상 right를 증가시킬 필요가 없습니다. 왜냐하면 누적합이기 때문에 right를 더 증가시켜 봤자 K가 되는 답을 구할 수 없으므로 이때 left를 증가시키면 됩니다. 따라서 이 문제는 투포인터로 해결할 수 있습니다.

 

 

 

<C++소스코드>

 

 

#include<iostream>
using namespace std;

int bar[1000001]; //bar[i] : [i - 1, i] 구간에 존재하는 막대기의 총길이
int main(void) {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	int n, k; cin >> n >> k;

	for (int i = 0; i < n; i++) { 
		int a, b; cin >> a >> b;
		bar[a]++; //막대기 시작점과 끝점 표현 -> [a, b]
		bar[b]--; 
	}
	for (int i = 1; i <= 1000000; i++) {
		bar[i] += bar[i - 1]; // [i-1, i] 구간에 존재하는 막대기의 총길이 계산
	}


	int right = 0;
	int sum = bar[0];
	for (int left = 0; left <= 1000000; left++) { // 현재 바라보는 구간 : [left, right]
		while (right + 1 < 1000000 && sum < k) { //막대기의 길이가 아직 k가 안 된 경우 
			right++;
			sum += bar[right]; // 늘어난 구간만큼(right) 막대기 총길이 누적
		}
		if (sum == k) { // k가 되는 구간을 찾으면 출력 후 종료
			cout << left << ' ' << right + 1 << '\n';
			return 0;
		}
		sum -= bar[left]; // 더이상 right를 증가시켜도 만족하는 구간이 없으므로 left를 증가시키면서 구간을 감소, 줄어든 구간만큼(left) 막대기 총길이 감소
	}
	cout << 0 << ' ' << 0; //k가 되는 구간이 존재하지 않는 경우


	return 0;
}
 
반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 1774번] 우주신과의 교감  (0) 2023.09.10
[백준 2056번] 작업  (0) 2023.09.01
[백준 17521번] Byte Coin  (0) 2023.04.24
[백준 1439번] 뒤집기  (0) 2023.04.23
[백준 20365번] 블로그2  (0) 2023.04.23

+ Recent posts