https://www.acmicpc.net/problem/5557
5557번: 1학년
상근이가 1학년 때, 덧셈, 뺄셈을 매우 좋아했다. 상근이는 숫자가 줄 지어있는 것을 보기만 하면, 마지막 두 숫자 사이에 '='을 넣고, 나머지 숫자 사이에는 '+' 또는 '-'를 넣어 등식을 만들며 놀
www.acmicpc.net
숫자가 주어졌을 때, +나 -를 끼워서 만들수 있는 올바른 등식의 개수를 출력하는 문제이다.
문제에서 등식의 개수는 2^63-1 이하라고 명시되어 있으므로 long long형을 이용해야한다.
이 문제는 처음에 일차원 dp로 구현하였다.
dp[i] : 현재 시점에서 계산값이 i가 나오는 경우의 수
n : 지금 입력받은 수
dp[i]>0 면, dp_copy[i+n]+=dp[i] or dp_copy[i-n] +=dp[i]dp_copy를 dp에 복사테케는 다 맞았지만, 아직까지 왜 틀렸습니다가 뜨는지 원인을 찾지 못했다 ㅠㅠ https://www.ioi-jp.org/joi/2010/2011-yo-prob_and_sol/index.html 의 4번문제 테스트케이스를 해보면 N=100일때만 답이 다른것을 확인하였다. 오버플로우 문제인가...?
일단 코드는 아래와 같다.
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int N, n;
long long dp[21] = { 1, };
long long dp_copy[21];
int main() {
	cin >> N;
	for (int i = 0; i < N; i++) {
		cin >> n;
		if (i == N - 1) {
			cout << dp[n] << endl;
			return 0;
		}
		memset(dp_copy, 0, sizeof(dp_copy));
		for (int j = 0; j < 21; j++) {
			if (dp[j] > 0) {
				int next;
				for (int k = 0; k < 2; k++) {
					if (k == 0) next = j + n;
					else next = j - n;
					if (next >= 0 && next <= 20) {
						dp_copy[next] += dp[j];
					}
				}
			}
		}
		copy(dp_copy, dp_copy + 21, dp);
	}
}
따라서, 일차원이 아닌 이차원 dp로 구현하였더니 해결되긴 하였다. 문제풀이 방식은 다음과 같다.
dp[i][j] : 0번째부터 i번째 인덱스까지 계산값이 j가 나오는 경우의 수
dp[i][j] = dp[i-1][j-a[i]] + dp[i-1][j+a[i]]
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int N,n;
long long dp[101][21]; //i번째 인덱스까지 j를 만드는 방법 
int a[101];
//dp[i][j] = dp[i-1][j-a[i]] + dp[i-1][j+a[i]]
int main() {
	cin >> N;
	for (int i = 0; i < N; i++) cin >> a[i];
	
	dp[0][a[0]] = 1; //맨처음수
	for (int i = 1; i < N-1; i++) {
		for (int j = 0; j <=20 ; j++) {
			int next;
			for (int k = 0; k < 2; k++) {
				if (k == 0) next = j+a[i]; 
				else next = j - a[i];
				if (next >= 0 && next <= 20) { //범위 내에있으면
					dp[i][next] += dp[i-1][j];
				}
			}
		}
	}
	cout << dp[N - 2][a[N - 1]];
}일차원이 틀렸던 이유는 더 고민해봐야겠다!
(추가)
맨처음 dp[0]을 1로 주고 for문을 돌리는것이 아닌, 맨 처음 숫자 n을 사용하여 dp[n]=1로 초기화 시킨후, 그다음부터 for문을 돌리면 처음 짯던 코드로 해결이 되었다!
원인은 이거였다. 맨처음 dp[0]=1로 초기화 시키면, 맨 처음 입력 숫자가 0일때 문제가 생긴다. 애초에 dp[0]=1에서 시작하기 때문에, 0이 들어오는 경우 0+0=0인 경우와 0-0=0인 경우로 dp[0]이 1이 아닌 2로 업데이트 되버린다.
원인을 찾아준 스터디원분께 감사의 말씀을 ㅠㅠ

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int N, n;
long long dp[21];
long long dp_copy[21];
int main() {
	cin >> N;
	cin >> n; dp[n] = 1;
	for (int i = 1; i < N; i++) {
		cin >> n;
		if (i == N - 1) {
			cout << dp[n] << endl;
			return 0;
		}
		memset(dp_copy, 0, sizeof(dp_copy));
		for (int j = 0; j < 21; j++) {
			if (j + n <= 20) dp_copy[j + n] += dp[j];
			if (j - n >= 0) dp_copy[j - n] += dp[j];
		}
		copy(dp_copy, dp_copy + 21, dp);
	}
}'Algorithm > DP' 카테고리의 다른 글
| [백준] 구간 합 구하기 5 (C++) (0) | 2021.10.08 | 
|---|---|
| [백준] 1753번 : 최단경로 (C++, 다익스트라) (0) | 2021.09.17 | 
| [프로그래머스] 정수 삼각형 (C++) (0) | 2021.09.16 | 
| [백준] 10164번 : 격자상의 경로 (0) | 2021.09.03 | 
| [백준] 1495번 : 기타리스트 (0) | 2021.08.31 | 
 
										
									 
										
									 
										
									 
										
									
댓글