二维背包

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;
}

 

posted @ 2019-02-25 10:09  月光下の魔术师  阅读(6)  评论(0)    收藏  举报