DP_동전 문제
4614 단어 ACM_데이터 구조ACM_DP
여기 서 먼저 가장 간단 한 동적 계획 인 스 턴 스 를 설명 한다. 동전 문제.다음 에 더 많은 인 스 턴 스 를 제공 할 것 입 니 다. 예 를 들 어 가장 긴 공공 서브 시퀀스, 가장 긴 공공 서브 문자열, 가장 긴 서브 시퀀스, 문자열 편집 거리 등 입 니 다.동적 계획 의 관건 은 '상태' 와 '상태 전이 방정식' 을 찾 는 것 이다.
동전 문제: 액면가 의 동전 을 드 리 고 N 값 을 드 리 겠 습 니 다. N 을 구성 하 는 데 필요 한 최소 동전 의 수량 과 방안 을 구 해 달라 고 합 니 다.분석: 이 문 제 는 욕심 산법 으로 해결 해 볼 수 있 습 니 다. 먼저 액면가 가 가장 큰 동전 부터 시도 하고 계속 찾 아 보 세 요. 동전 의 총 화 는 N 이라는 것 을 알 고 있 습 니 다.그러나 욕심 산법 은 해 를 찾 을 수 있다 고 장담 할 수 없다 (예 를 들 어 2, 3, 5, 그리고 N = 11).우 리 는 생각 을 바 꿀 수 있다. 우 리 는 d (i) 로 i 의 최소 동전 수량 (사실은 동적 계획 중의 '상태') 을 나타 낸다. 그러면 어떻게 앞의 상태 (반드시 d (i - 1) 라 는 상태 가 아니 라 d (i) 라 는 상태 까지?동전 집합 이 coins [0 ~ N] 이 라 고 가정 하면 d (i) 를 구하 기 전에 우 리 는 d (1 ~ i - 1) 를 모두 구 했다 고 가정 하면 d (i) = min {d (j) + 1}, if i - j 는 coins 에서 (사실은 이것 이 '상태 전이 방정식') 이다.달리 우 리 는 모든 액면 가 를 하나의 점 으로 본다!충분 한 액면가 가 필요 하 다 는 뜻 으로 초기 상 태 는 S, 목표 상 태 는 0 이다.그러면 현재 상태 가 i 이면 동전 j 를 사용 할 때마다 상태 가 i - Vj 로 전 이 됩 니 다.
예 를 들 어 coins = {2, 3, 5}, N = 11.
d(0)=0;
d(1)=0;
d(2)=d(0)+1=1;
d(3)=d(0)+1=1;
d(4)=d(2)+1=2;
d(5)=min{d(3)+1,d(2)+1,d(0)+1}=1;
d(6)=min{d(4)+1,d(3)+1}=2;
.......................
또한 마지막 방안 (동전 개수 뿐만 아니 라) 을 구하 기 위해 서 는 각 상태 에서 선택 한 '경로' 를 기록 해 야 한다. 예 를 들 어 d (5) 를 구하 기 위해 우 리 는 d (0) + 1 을 선택 했다. 그러면 우리 가 선택 한 경 로 는 5 - 0 = 5 이다.우 리 는 이 경 로 를 기록 한 후에 경로 에 따라 결 과 를 얻어 야 한다.d (6) 에 대해 우 리 는 3 을 선택 하기 시작 했다. 즉, 우 리 는 d (3) 상태 와 동전 3 에서 d (6) 로 넘 어 가 는 것 을 선택 했다. 이 어 d (3) 에 대해 우 리 는 3 을 선택 했다. 즉, 우 리 는 d (0) 상태 와 동전 3 에서 d (3) 로 넘 어 가 는 것 을 선택 했다. 이 어 d (0) 에 대해 이것 은 초기 상태 이다.그 러 니까 우리 방안 은 3, 3.
푸 시 (최소 순서 인쇄):
#include
#include
using namespace std;
const int MAXN = 10000;
const int INF = 1000000000;
int n, S, V[MAXN], minn[MAXN], maxn[MAXN];
//minn[i] i , !maxn[i] i , !
void print_ans(int* d, int S) {
for(int i = 1; i <= n; ++i) {
if(S >= V[i] && d[S] == d[S - V[i]] + 1){ // !
cout << i << " ";
print_ans(d, S-V[i]);
break; // !
}
}
}
int main() {
cin >> n >> S;
for(int i = 1; i <= n; ++i) {
cin >> V[i];
}
for(int i=1; i<=S; ++i){
minn[i]=INF;maxn[i]=-INF;
}
for(int i=1; i<=S; ++i)
printf("minn=%d
",minn[i]);
for(int i = 1; i <= S; ++i) { // ! minn[1...S] maxn[1...S]!
for(int j = 1; j <= n; ++j) {
if(i >= V[j]) {
minn[i] = min(minn[i], minn[i - V[j]] + 1);
maxn[i] = max(maxn[i], maxn[i - V[j]] + 1);
}
}
}
cout << minn[S] << endl;
cout << maxn[S] << endl;
print_ans(minn, S);
cout << endl;
print_ans(maxn, S);
cout << endl;
return 0;
}
다른 인쇄 방식:
#include
#include
using namespace std;
const int MAXN = 10000;
const int INF = 1000000000;
int n, S, V[MAXN], minn[MAXN], maxn[MAXN];
//minn[i] i , !maxn[i] i , !
int min_coin[MAXN], max_coin[MAXN];
//min_coin[S] minn[S] = minn[S-V[i]]+1 i。
void print_ans(int* d, int S) {
while(S) {
cout << d[S] << " ";
S -= V[d[S]];
}
}
int main() {
cin >> n >> S;
for(int i = 1; i <= n; ++i) {
cin >> V[i];
}
for(int i=1; i<=S; ++i){
minn[i]=INF;maxn[i]=-INF;
}
for(int i = 1; i <= S; ++i) { // ! minn[1...S] maxn[1...S]!
for(int j = 1; j <= n; ++j) {
if(i >= V[j]) {
if(minn[i] > minn[i - V[j]] + 1) {
minn[i] = minn[i - V[j]] + 1;
min_coin[i] = j;
}
if(maxn[i] < maxn[i - V[j]] + 1) {
maxn[i] = maxn[i - V[j]] + 1;
max_coin[i] = j;
}
}
}
}
cout << minn[S] << endl;
cout << maxn[S] << endl;
print_ans(min_coin, S);
cout << endl;
print_ans(max_coin, S);
cout << endl;
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
POJ - 2104 주석 나무 판자That is, given an array a[1…n] of different integer numbers, your program must answer a series of questions Q(i, j, k) i...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.