https://www.acmicpc.net/problem/1699
0. 시행착오
1. dp[104]로 선언해놓고 for(int i=0~104)로 초기화 -> out of bound...
2. 2중for문 100000 * 100000 으로 해놓고 왜안됨? 뻘짓..
1. 수학으로 시간복잡도줄이기
문제 : i의 범위 100000 * j의 범위 100000 -> 시초
해결 : i의범위는 root n <n / root 4 < 4 이므로 i는 root n까지만 탐색해도된다.
2. 의사코드
초기화 : 초록형광색부분을 초기값으로 초기화한다.
j행에 1~target을 놓고
i행에 주머니, 코인등을 추가시키면서 규칙성(화살표)을찾는다.
dp = min(위쪽, dp[j-i])임을 발견한다.
3. dp 2차원 to 1차원
위쪽을 확인하는 것은 자기자신을 확인하는것과 같다. //위쪽확인대신 자기자신을 확인하면 된다.
dp[i-1][j] == dp[j]
3. 전체코드
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,dp[100004];
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n;
//dp[i][j] : i자연수 추가시 j를만드는 행의 최소갯수
for (int j = 1; j < 100000; ++j) dp[j] = j;
for (ll i = 2; i*i <= n; ++i) {
ll a = i * i;
for (int j = 1; j <= n; ++j) {
if (j - a >= 0) {
dp[j] = min(dp[j], dp[j - a] + 1);
}
/*else
dp[j] = dp[j];*/
}
}
/*for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= n; ++j) {
cout << dp[i][j]<<" ";
}
cout << "\n";
}*/
cout << dp[n];
return 0;
}
4. 추가개선
j-a가 음수인 범위는 사실상 위쪽을 그대로 가져다 씀 -> j를 a(i*i)부터 시작하면
20%의 시간단축이 있다.
'Algorithm > dp' 카테고리의 다른 글
백준 15486 퇴사2 c++ // 탑다운디피, 재귀디피, 맨뒤에서오는 노드그림을 떠올려라! (0) | 2024.04.26 |
---|---|
백준 2240 자두나무 c++ // 탑다운디피, 재귀디피 형식, 비트연산자, memset사용법 (0) | 2024.04.26 |
백준 11052 카드구매하기 c++ //dp 관찰방법 (0) | 2024.04.15 |
백준 1912 연속합 c++ // dp, 규칙발견, ox를 그때그때 선택해버리기 (0) | 2024.04.15 |
백준 11053 LIS c++ // dp, 규칙발견, 일반화 (0) | 2024.04.15 |