가방2016.5.1
제목
N 개 아이템과 V 가방 1개가 있습니다.
i번째 아이템을 넣는 데 소모되는 공간은 Ci이고, 얻는 가치는 Wi입니다.
어떤 아이템을 가방에 넣으면 가치 총합이 최대
2. 기본적인 사고방식
특징:
모든 물품은 하나뿐이니 놓든지 말든지 선택할 수 있다
하위 문제를 사용하여 상태를 정의하려면 다음과 같이 하십시오.
dp[i, V]는 앞의 i개 아이템을 용량이 v인 가방에 넣으면 얻을 수 있는 최대 가치를 나타낸다.
그러면 그 상태 이동 방정식은 다음과 같다. dp[i, V] = max{dp[i -3 1, V], dp[i -3 1, V -3 Ci] + Wi}
해석하다
"앞의 i개 아이템을 V 가방에 넣기"질문
i번째 아이템만 고려하는 전략(놓거나 놓지 않음)
그러면 전 i-3-1개 물품과 관련된 문제로 바뀔 수 있다
만약 i번째 아이템을 넣지 않는다면 문제는'전 i-3-1 아이템을 용량이 V인 가방에 넣기'로 바뀌고 가치는 dp[i-3-1, V]
i번째 아이템을 넣으면 문제는'앞의 i-3-1 아이템을 남은 용량의 V-3 Ci 가방에 넣기'로 바뀐다.
이때 얻을 수 있는 가장 큰 가치는 dp[i -3 1, V -3 C이다.
i] 여기에 i번째 아이템을 넣으면 얻을 수 있는 가치 W
i
POJ 3624 Charm Bracelet
//시간과 공간의 복잡성은 O(V * N)
//Result:MLE
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 3410;
int W[maxn];
int D[maxn];
int dp[maxn][12890];
int main()
{
// freopen("in.txt", "r", stdin);
int N, M;
scanf("%d%d", &N, &M);
for (int i=1; i<=N; ++i) {
scanf("%d%d", &W[i], &D[i]);
}
memset(dp, 0, sizeof(dp));
for (int i=1; i<=N; ++i) {
for (int j=1; j<W[i]; ++j) {
dp[i][j] = dp[i-1][j];
}
for (int j=W[i]; j<=M; ++j) {
dp[i][j] = max(dp[i-1][j-W[i]] + D[i], dp[i-1][j]);
}
}
printf("%d
", dp[N][M]);
return 0;
}
3. 공간 복잡도 최적화
이상의 방법의 시간과 공간 복잡도는 모두 O(V*N)이다. 그 중에서 시간 복잡도는 더 이상 최적화할 수 없지만 공간 복잡도는 O(V)로 최적화할 수 있다.
위의 기본적인 사고방식: 하나의 주순환 i=1...N, 매번 2차원 그룹 dp[i, 0.V]의 모든 값을 계산한다
그러면 만약에 하나의 수조 dp[0.V]만 사용한다면 i차 순환이 끝난 후 dp[V]에서 우리가 정의한 상태 dp[i,V]를 나타낼 수 있을까요?
dp[i, v]는 dp[i -3 1, v]와 dp[i -3 1, v -3 Ci] 두 개의 하위 문제가 점차 밀려왔다.
dp[i, v]를 추측할 때(즉 i차 주순환에서 dp[v]를 추측할 때) dp[i-3-1, v]와 dp[i-3-1, v-3]의 값을 사용할 수 있음을 보장할 수 있습니까?
사실상, 이것은 매번 주 순환에서 우리가 v=V..0의 체감 순서로 dp[v]를 계산하도록 요구한다
이렇게 해야만 dp[v]를 추측할 때 dp[v-3Ci]가 저장한 상태 dp[i-3-1, v-3Ci]의 값을 보장할 수 있다
POJ 3624 Charm Bracelet
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 3410;
int W[maxn];
int D[maxn];
int dp[12890];
int main()
{
// freopen("in.txt", "r", stdin);
int N, M;
scanf("%d%d", &N, &M);
for (int i=1; i<=N; ++i) {
scanf("%d%d", &W[i], &D[i]);
}
memset(dp, 0, sizeof(dp));
for (int i=1; i<=N; ++i) {
for (int j=M; j>=W[i]; --j) {
if (dp[j-W[i]] + D[i] > dp[j]) {
dp[j] = dp[j-W[i]] + D[i];
}
}
}
printf("%d
", dp[M]);
return 0;
}
4. 초기화된 세부 문제
가장 잘 풀리는 배낭 문제 중에는 사실상 두 가지 그다지 같지 않은 문법이 있다
어떤 문제는'배낭을 꼭 채우라'고 요구했을 때 가장 잘 풀렸고, 어떤 문제는 반드시 등을 가득 채워야 한다고 요구하지 않았다.
이 두 가지 문법의 실현 방법은 초기화할 때 다소 다르다
만약 첫 번째 질문법이라면, 가방에 꼭 채워야 합니다.
그러면 초기화할 때 dp[0]가 0인 것을 제외하고 다른 dp[1.V]는 모두 -3-∞로 설정하면 최종적으로 얻은 dp[V]가 가방을 꼭 채우는 가장 좋은 방법이라는 것을 보장할 수 있다.
만약 반드시 등을 가득 채워야 한다고 요구하지 않았다면, 다만 가격이 될 수 있는 대로 크기를 바랄 뿐이다
초기화할 때 dp[0.V]를 모두 0으로 설정해야 합니다.
왜 그런 걸까요?다음과 같이 이해할 수 있습니다.
초기화된 F수 그룹은 사실 가방에 넣을 수 있는 아이템이 없을 때의 합법적인 상태입니다
가방이 꼭 채워져야 한다면, 이때 용량이 0인 가방만 아무것도 넣지 않고 가치가 0인 상황에서'꼭 채워야 한다'
기타 용량의 가방은 모두 합법적인 해가 없고 정의되지 않은 상태에 속하므로 -∞로 부여되어야 한다
만약 배낭이 반드시 가득 채워져야 하는 것이 아니라면, 어떤 용량의 배낭도 모두 합법적으로 '아무것도 넣지 않는다' 라고 풀 수 있다
이 해의 가치는 0이기 때문에 초기 상태의 값도 모두 0이다
다섯, 소결
01 가방 문제는 가장 기본적인 가방 문제
그것은 배낭 문제 중 설계 상태, 방정식의 가장 기본적인 사상을 포함하고 있다
또한, 다른 유형의 가방 문제도 01 가방 문제로 변환하여 해답을 구할 수 있다
그러므로 상기 기본적인 사고방식의 도출 방법, 상태 이동 방정식의 의미, 그리고 공간의 복잡도가 어떻게 최적화되는지 반드시 자세하게 체득해야 한다.
<가방 9강 V 2.0>%%% 저자, 작가에게 감사
HDU 2602 Bone Collector
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn = 100 + 10;
double Pj[maxn];
int Mj[maxn];
double dp[10010];
int main()
{
#ifdef __AiR_H
freopen("in.txt", "r", stdin);
#endif // __AiR_H
int T;
while (scanf("%d", &T) != EOF) {
while (T--) {
double P;
int N;
int sum = 0;
scanf("%lf%d", &P, &N);
for (int i = 1; i <= N; ++i) {
scanf("%d%lf", &Mj[i], &Pj[i]);
sum += Mj[i];
}
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (int i = 1; i <= N; ++i) {
for (int j = sum; j >= Mj[i]; --j) {
dp[j] = max(dp[j], dp[j - Mj[i]] * (1 - Pj[i]));
}
}
for (int i = sum; i >= 0; --i) {
if (dp[i] >= (1-P)){
printf("%d
", i);
break;
}
}
}
}
return 0;
}
HDU 2546 식사 카드
문제 해결 방법:
마지막으로 가장 비싼 요리를 사자(여러 개 있을 수 있다)
그리고 브이=m-5를 구하고 첫 번째 비싼 음식을 고려하지 않는 01배낭 문제
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1000 + 10;
int price[maxn];
int dp[1010];
int main()
{
#ifdef __AiR_H
freopen("in.txt", "r", stdin);
#endif // __AiR_H
int n;
while (scanf("%d", &n) != EOF && n != 0) {
int Max;
int t;
for (int i = 1; i <= n; ++i) {
scanf("%d", &price[i]);
if (i == 1) {
Max = price[i];
t = 1;
} else if (price[i] > Max) {
Max = price[i];
t = i;
}
}
int m;
scanf("%d", &m);
if (m < 5) {
printf("%d
", m);
} else {
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; ++i) {
if (i != t) {
for (int j = m-5; j >= price[i]; --j) {
dp[j] = max(dp[j], dp[j-price[i]] + price[i]);
}
}
}
printf("%d
", m-dp[m-5]-Max);
}
}
return 0;
}
HDU 1171 Big Event in HDU
V=halves로 전환 01 가방 문제
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 50 + 10;
int V[maxn];
int M[maxn];
int dp[130000];
int main()
{
#ifdef __AiR_H
freopen("in.txt", "r", stdin);
#endif // __AiR_H
int N;
while (scanf("%d", &N) != EOF && N >= 0) {
int sum = 0;
for (int i = 1; i <= N; ++i) {
scanf("%d%d", &V[i], &M[i]);
sum += (V[i] * M[i]);
}
int halves = sum / 2;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= N; ++i) {
for (int j = 0; j < M[i]; ++j) {
for (int k = halves; k >= V[i]; --k) {
dp[k] = max(dp[k], dp[k-V[i]] + V[i]);
}
}
}
printf("%d %d
", sum-dp[halves], dp[halves]);
}
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.