문제링크 : https://www.acmicpc.net/problem/2629
2629번: 양팔저울
첫째 줄에는 추의 개수가 자연수로 주어진다. 추의 개수는 30 이하이다. 둘째 줄에는 추의 무게들이 자연수로 가벼운 것부터 차례로 주어진다. 같은 무게의 추가 여러 개 있을 수도 있다. 추의 무
www.acmicpc.net
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 987654321;
int N, guseul, w;
int arr[31];
int dp[31][40001];
void func(int idx, int weight)
{
if(idx>N || dp[idx][weight]) return;
dp[idx][weight]=1;
func(idx+1, weight+arr[idx]); //i번째 무게추를 구슬쪽 저울에 올림
func(idx+1, abs(weight-arr[idx])); //i번째 무게추를 구슬 반대편 저울에 올림
func(idx+1, weight); //i번째 무게추를 올리지 않음
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for(int i=0; i<N; i++)
{
cin >> arr[i]; //추의 무게
}
cin >> guseul;
func(0, 0);
for(int i=0; i<guseul; i++)
{
cin >> w; //확인해야 하는 무게
cout << (dp[N][w] ? "Y " : "N ");
}
return 0;
}
해당 문제의 경우 경우의 수가 아래와 같이 3가지가 있다.
1. 저울에 구슬과 같이 무게추를 올림
2. 구슬 반대편 저울에 무게추를 올림
3. 무게추를 올리지 않음
각 케이스에 대해 3가지 경우의 수를 검토해주고 또 나온 결과에 대해서 3가지 경우의 수를 검토해주는 것을 반복한다.
중복한 결과에 대해서 다시 탐색할 수 있으므로 현재 dp[idx][weight]가 1이라면 바로 종료시켜준다. (시간초과 방지)
그리고 idx과 weight를 넘겨주는데 idx가 N을 넘어서면 안되므로 해당 경우에도 종료시켜주도록 한다.
검토한 케이스에 대해서 우리가 확인해야 하는 dp[N][w]의 값이 1이라면 가능하다는 것이므로 Y를 출력하고 검토당시 불가능했다면 0이 담겨있으므로 N을 출력한다.
참고로 위 문제에서 dp 배열을 [31][40001]으로 선언해주었으나, 무게의 합이 최대 15000(30*500)이므로 15000까지만 선언하고 x가 15000이 넘을 때 바로 N이 되도록 해주면 메모리가 절약된다. (x의 입력자체는 40000만까지 가능)
해당 문제는 재귀말고도 반복문을 통해서 풀 수 있었으므로 다음 방식으로도 풀어보았다.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 987654321;
int N, guseul, w, sum;
int arr[31];
int dp[31][40001];
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for(int i=0; i<N; i++)
{
cin >> arr[i]; //추의 무게
sum+=arr[i]; //무게 합 저장
}
dp[0][0] = dp[0][arr[0]] = 1; //구슬 할당을 하는가 안하는가
for(int i=1; i<N; i++)
{
for(int j=0; j<=sum; j++)
{
if(!dp[i-1][j]) continue;
dp[i][j+arr[i]] = 1; //i번째 무게추를 구슬쪽 저울에 올림
dp[i][abs(j-arr[i])] = 1; //i번째 무게추를 구슬 반대편 저울에 올림
dp[i][j]=1; //아무것도 하지 않음
}
}
cin >> guseul;
for(int i=0; i<guseul; i++)
{
cin >> w; //확인해야 하는 무게
cout << (dp[N-1][w] ? "Y " : "N ");
}
return 0;
}
핵심 내용은 3가지 경우의 수를 탐색해주는 것으로 위와 동일하다.
여기서는 처음에 초기화를 2가지를 해주고 시작한다.
구슬 할당 o : dp[0][arr[0]]
구슬 할당 x : dp[0][0]
구슬 할당을 했을 때와 안 했을 때 2가지로 나눠서 미리 초기화를 시켜주고 진행한다.
직전값이 1일 때 즉 저번값에 이어서 탐색이 가능할때 이어서 3가지 경우의 수에 대해 탐색을 해준다.
'백준 > 골드' 카테고리의 다른 글
[백준 2623번] 음악프로그램 (C++) (0) | 2023.10.04 |
---|---|
[백준 1005번] ACM Craft (C++) (0) | 2023.10.03 |
[백준 4781번] 사탕 가게 (C++) (0) | 2023.09.28 |
[백준 7579번] 앱 (C++) (0) | 2023.09.27 |
[백준 2056번] 작업 (C++) (0) | 2023.09.26 |