二维背包
POJ2576
题解:
限制为人数和体重。人数差距不能超过1,体重越近越好。
dp[i][j][k]表示考虑第i个人,能否达到人数为j,体重为k的状态。跑二维01背包最后再枚举各个状态,优先考虑人数,其次考虑体重
代码:
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
int const inf = 0x7f7f7f7f;
int const N = 100 + 10;
int const M = 45000;
int weight;
bool dp[M][N];
int n;
int main(){
scanf("%d",&n);
int sum = 0;
dp[0][0] = true; //初始化,体重为0,人数为0是一定可以取到的。
for(int i=1;i<=n;i++){
scanf("%d",&weight);
sum += weight;
for(int j=i*450;j>=0;j--){ //体重上限为假设前面几个人每个人都取最大的体重
for(int k=i;k>=0;k--){ //人数
dp[j][k] = dp[j][k];
if(j >= weight && k >= 1) dp[j][k] = dp[j][k] || dp[j-weight][k-1];
}
}
}
int half = n / 2;
int p1 = 0,p2 = M;
for(int i=sum;i>=0;i--){ //枚举体重
if(dp[i][half]){
int t1 = min(i,sum-i), t2 = max(i,sum-i);
if(p2-p1 >= t2-t1) p1 = t1,p2 = t2;
}
}
printf("%d %d\n",p1,p2);
return 0;
}
HDU2159
题解:
两个费用分别为忍耐度和杀敌数量
dp[i][j][k]表示考虑到第i只怪,忍耐度和杀敌数量的容量分别为j,k的情况下的最大经验
完全背包问题,二维顺序
因为是剩下的最大忍耐度,所以循环j,k当经验超过限定的时候输出并break;
代码:
#include <bits/stdc++.h>
using namespace std;
int const N = 100 + 10;
int n,m,k,v,s;
int val[N],weight[N];
int dp[N][N];
int main(){
while(~scanf("%d%d%d%d",&v,&m,&n,&s)){
for(int i=1;i<=n;i++)
scanf("%d%d",&val[i],&weight[i]);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
for(int j=weight[i];j<=m;j++){
for(int k=1;k<=s;k++)
dp[j][k] = max(dp[j][k],dp[j-weight[i]][k-1] + val[i]);
}
}
bool flag = true;
for(int i=1;i<=m && flag;i++){
for(int j=1;j<=s && flag;j++){
if(dp[i][j] >= v){
printf("%d\n",m - i);
flag = false;
}
}
}
if(flag) printf("%d\n",-1);
}
return 0;
}

浙公网安备 33010602011771号