-
2024-03-14PS(알고리즘 문제풀이) 관련 글/PS일지 2024. 3. 14. 22:41
-파일 합치기(13975, 백준)
쉬운 우선순위 큐 응용 문제이다. 모든 파일들을 하나로 합칠 때의 최소 비용은 항상 가장 작은 수 둘을 합치는 과정을 반복하는 것이다. 따라서 입력받은 수를 최소 우선순위 큐에 넣은뒤, 큐에서 수가 하나남을때까지 두개를 빼서 합친뒤 다시 넣기를 반복해준다. 이 과정에서 발생하는 비용을 처리해주면 된다.
<소스 코드>
더보기#include <stdio.h> #include <algorithm> #include <queue> using namespace std; int main() { int t; scanf("%d", &t); while (t--) { int i, n; scanf("%d", &n); priority_queue<long long> pq; for (i = 0; i < n; i++) { long long x; scanf("%lld", &x); pq.push(-x); } long long res = 0; while (pq.size() > 1) { long long x = -pq.top(); pq.pop(); long long y = -pq.top(); pq.pop(); pq.push(-(x + y)); res += x + y; } printf("%lld\n", res); } }
-서강 그라운드 (14938, 백준)
쉬운 다익 문제이다. 낙하산에서 떨어진 위치에서부터 주어진 범위 m안에 있는 모든 아이템을 먹을 수 있음으로, 착륙지점에서부터 다익을 돌린다. 그 후, 떨어진 지점에서부터 최소 거리가 m보다 작거나 같은 노드에있는 아이템을 더해준다.
<소스 코드>
더보기#include <stdio.h> #include <algorithm> #include <vector> #include <queue> using namespace std; int n, m, r; vector <pair<int, int>> vec[110]; int arr[110], dis[110]; void Dijkstra(int s) { int i, j; priority_queue <pair<int, int>> pq; pq.push({0, s}); dis[s] = 0; while(!pq.empty()) { int nidx = pq.top().second, nval = -pq.top().first; pq.pop(); if(dis[nidx] < nval) continue; for(i=0;i<vec[nidx].size();i++) { int idx = vec[nidx][i].first; int val = nval + vec[nidx][i].second; if(dis[idx] > val) { dis[idx] = val; pq.push({-val, idx}); } } } } int main() { int i, j; scanf("%d %d %d", &n, &m, &r); for(i=1;i<=n;i++) scanf("%d", &arr[i]); for(i=0;i<r;i++) { int x, y, z; scanf("%d %d %d", &x, &y, &z); vec[x].push_back({y, z}); vec[y].push_back({x, z}); } int ans = -2e9; for(i = 1;i<=n;i++) { for(j=0;j<=n;j++) dis[j] = 2e9; Dijkstra(i); int res = 0; for(j=1;j<=n;j++) if(dis[j] <= m) res += arr[j]; ans = max(res, ans); } printf("%d", ans); return 0; }
-면접보는 승범이네(17835, 백준)
다익 문제이다. 면접장이 여러 군데 존재함으로, 한군데 한군데에서 다익을 돌리면 최악의 경우 O(N^2)으로 시간초과가 떠버릴 수 있기에 모든 면접장을 큐에 먼저 넣어둔 뒤, 다익을 돌리면 된다. 면접장에서부터 집까지의 거리가 아니기 때문에, 노드를 역순으로 집어넣어 직장에서부터 도시까지의 거리를 구하면 답이 나오게 바꾸어 준다.
※숫자의 범위와 초기값에 주의하자.
<소스 코드>
더보기#include <stdio.h> #include <queue> #include <vector> using namespace std; long long n, m, k; vector <pair<long long, long long>> vec[100010]; priority_queue <pair<long long, long long>> pq; long long dis[100010]; void Dijkstra() { long long i, j; while (!pq.empty()) { long long nidx = pq.top().second, nval = -pq.top().first; pq.pop(); if (dis[nidx] < nval) continue; for (i = 0; i < vec[nidx].size(); i++) { long long idx = vec[nidx][i].first, val = nval + vec[nidx][i].second; if (dis[idx] > val) { dis[idx] = val; pq.push({ -val, idx }); } } } } int main() { long long i, j; scanf("%lld %lld %lld", &n, &m, &k); for (i = 1; i <= n; i++) dis[i] = 2e19; for (i = 0; i < m; i++) { long long x, y, z; scanf("%lld %lld %lld", &x, &y, &z); vec[y].push_back({ x, z }); } for (i = 0; i < k; i++) { long long x; scanf("%lld", &x); dis[x] = 0; pq.push({ 0, x }); } Dijkstra(); long long mx = -1, ans = 0; for (i = 1; i <= n; i++) if (mx < dis[i]) mx = dis[i], ans = i; printf("%lld\n%lld", ans, mx); return 0; }
-불켜기(11967, 백준)
최댈한 불을 얼마나 킬 수 있는지 구하는 문제이다. 무작정 불이 켜진 곳을 넣어주지 말고, 갈 수 있는 지점만 queue에 집어넣어주는 것이 좋다. 불을 킬때, 4방향 탐색을 통해 4방향중 한곳이라도 전에 방문을 했다면 queue에 넣어준다. queue에서 수를 꺼낼 때 또한 4방향 탐색후 불이 켜지지않고, 방문하지 않은 곳을 찾아 queue에 넣어준다. 이렇게 하면 불을 킬 때마다 인접한 4방향을 검사해가며 BFS를 통해 문제를 해결 할 수 있다.
<소스 코드>
더보기#include <stdio.h> #include <algorithm> #include <vector> #include <queue> using namespace std; int n, m; vector <pair<int, int>> vec[110][110]; int vis[110][110], light[110][110]; int res; int dx[5] = { 0, 0, 1, -1 }; int dy[5] = { 1, -1, 0, 0 }; int main() { int i, j; scanf("%d %d", &n, &m); for (i = 0; i < m; i++) { int x, y, a, b; scanf("%d %d %d %d", &x, &y, &a, &b); vec[x][y].push_back({ a, b }); } queue <pair<int, int>> q; q.push({ 1, 1 }); vis[1][1] = 1; light[1][1] = 1; res++; while (!q.empty()) { int n_x = q.front().first, n_y = q.front().second; q.pop(); for (i = 0; i < vec[n_x][n_y].size(); i++) { int nx = vec[n_x][n_y][i].first; int ny = vec[n_x][n_y][i].second; if (light[nx][ny] == 1) continue; light[nx][ny] = 1; res++; for (j = 0; j < 4; j++) { int nox = nx + dx[j], noy = ny + dy[j]; if (nox < 1 || noy < 1 || nox > n || noy > n) continue; if (vis[nox][noy] == 1) { vis[nx][ny] = 1; q.push({ nx, ny }); break; } } } for (i = 0; i < 4; i++) { int nx = n_x + dx[i], ny = n_y + dy[i]; if (nx < 1 || ny < 1 || nx > n || ny > n) continue; if (light[nx][ny] == 0 || vis[nx][ny] == 1) continue; vis[nx][ny] = 1; q.push({ nx, ny }); } } printf("%d", res); return 0; }
-가계부(Hard)(12837, 백준)
세그먼트 트리를 0으로 구성한 후, 주어지는 쿼리에따라 수정과 합 출력을 반복하면 된다. 세그트리를 풀어봤다면 쉽게 풀린다.
<소스 코드>
더보기#include <stdio.h> #include <algorithm> #include <vector> using namespace std; long long n, Q; long long segtree[4000010]; long long sum(long long s, long long e, long long low, long long high, long long node) { if(e < low || high < s) return 0; if(low <= s && e <= high) return segtree[node]; long long mid = (s + e)/2; return sum(s, mid, low, high, node*2) + sum(mid + 1, e, low, high, node*2+1); } void edit(long long s, long long e, long long idx, long long node, long long dis) { if(idx < s || idx > e) return; segtree[node] += dis; if(s != e) { long long mid = (s + e) / 2; edit(s, mid, idx, node*2, dis); edit(mid+1, e, idx, node*2+1, dis); } } int main() { long long i, j; scanf("%lld %lld", &n, &Q); for(i=0;i<Q;i++) { long long x, y, z; scanf("%lld %lld %lld", &x, &y, &z); if(x == 1) edit(1, n, y, 1, z); else if(x == 2) printf("%lld\n", sum(1, n, y, z, 1)); } }
'PS(알고리즘 문제풀이) 관련 글 > PS일지' 카테고리의 다른 글
2024-03-16 (0) 2024.03.16 2024-03-15 (0) 2024.03.15 2024-03-13 (0) 2024.03.13 2024-03-12 (1) 2024.03.12 2024-03-11 (1) 2024.03.11