halang-log
💡 PS

[SWEA] 10806. 수 만들기

date
Jul 27, 2023
slug
making-number
author
status
Public
tags
dijkstra
PS
summary
수 만들기 문제에 대한 풀이입니다.
type
Post
thumbnail
category
💡 PS
updatedAt
Aug 3, 2023 06:39 AM
언어

문제

풀이

이 문제는
  1. X에 D를 더하거나
  1. D에 어떤 수를 곱해서
X를 K로 만들어야 하는 문제입니다.
 
D는 어떤 수를 계속 곱해주거나 그대로이기 때문에 어떤 수를 곱해준 D의 배수가 K가 안된다면 D에 곱해주면 안됩니다. 문제 예시 입력중 두번째 케이스를 봅시다.
 
A = [3], X = 0, D = 1, K = 16입니다.
 
D = 1, K = 16
D = 1, K = 15 → 여기서 D에 3을 곱해주지 않은 이유는 3을 곱해버리면 16이라는 수를 만들 수 없습니다.
D = 3, K = 15 → 여기서 D에 3을 곱해준 이유는 15가 3의 배수이기 때문에 5번 더하면 15를 만들어 줄 수 있기 때문입니다. (그리고 곱해주는게 무조건 이득입니다.)
D = 3, K = 12 → 여기서 D에 3을 곱해주지 않은 이유는 3을 곱해버리면 9가 되는데 9를 여러번 더해 15라는 수를 만들 수 없기 때문입니다. 따라서 D를 빼주었습니다 (15 - 3)
D = 3, K = 9 → 여기서 D에 3을 곱해주지 않은 이유는 9를 여러번 더해 12라는 수를 만들 수 없기 떄문입니다.
D = 9, K = 9 → 여기서 D에 3을 곱해준 이유는 9가 9의 배수이기 때문입니다.
 
따라서 총 4번 빼주었기 때문에 답은 4가 됩니다.
 
여기서 한가지 중요한 아이디어가 있습니다. 바로,
D = 3, K = 15
D = 1, K = 5
두 경우를 같은걸로 취급할 수 있다는 것입니다.
 
15 - 3 - 3 - 3 - 3 - 3 = 0 은
5 - 1 - 1 - 1 - 1 - 1 = 0과 같은거랑 동치입니다.
 
그럼 D = 3, K = 15를 D = 1, K = 5로 보고 이후 과정을 다시 봅시다.
D = 1, K = 5
D = 1, K = 3 → 여기서 D에 3을 곱해주지 않은 이유는 3을 곱해버리면 5라는 수를 만들 수 없습니다. 그리고 K를 1 빼기보다 3의 배수가 되게 빼주는게 이득입니다. 따라서 K - 2 = 3을 해줍니다.
D = 3, K = 3
 
이렇게 해도 총 4번 빼주었기 때문에 답은 똑같이 4가 됩니다.
 
이를 이용해 K에서 0으로 가는 최단거리 문제로 볼 수 있습니다. D에 배열 A의 원소를 곱한다는 것을 역으로 K에 배열 A의 원소를 나눈다 라고 생각할 수 있습니다. 만약 배열 A의 원소에 있는 수와 나눠 떨어진다면 비용은 들지 않게 되고, 나눠 떨어지지 않는다면 나눠 떨어지는 수로 만들고 그 만큼의 비용을 더해주면 됩니다.
그냥 단순히 배열로 거리를 확인하면 메모리가 굉장히 커지기 때문에(10^9라서) unordered_map을 이용해 확인해주었습니다.
 

코드

#include <iostream> #include <cstdio> #include <algorithm> #include <queue> #include <map> #include <unordered_map> using namespace std; int tc; void go() { int n, k, arr[11]; scanf("%d", &n); unordered_map<int, int> mp; priority_queue<pii, vector<pii>, greater<pii>> pq; for (int i = 0; i < n; i++) { scanf("%d", &arr[i]); } scanf("%d", &k); pq.push({0, k}); mp[k] = 0; while (!pq.empty()) { int cost = pq.top().first, cur = pq.top().second; pq.pop(); if (cur == 0) { printf("%d\n", cost); return; } for (int i = 0; i < n; i++) { if ((cur % arr[i]) == 0) { if (mp.find(cur/arr[i]) != mp.end() and mp[cur/arr[i]] <= cost) continue; pq.push({cost, cur / arr[i]}); mp[cur/arr[i]] = cost; } else if (cur - (cur % arr[i]) >= 0) { if (mp.find(cur-(cur%arr[i])) != mp.end() and mp[cur-(cur%arr[i])] <= cost + (cur % arr[i])) { continue; } pq.push({cost + (cur % arr[i]), cur - (cur % arr[i])}); mp[cur-(cur%arr[i])] = cost + (cur % arr[i]); } } } } int main() { scanf("%d", &tc); for(int i = 1; i <= tc; i++) { printf("#%d ", i); go(); } }