一:0-1背包问题
#include<iostream>
#include<algorithm>
#include<cstring>
const int maxn=100;
using namespace std;
int w[maxn];
int p[maxn];
int x[maxn];
int c[maxn][maxn];
int kanpsack_1(int n,int m){
for(int i=0;i<=m;i++){
c[0][i]=0;
}
for(int j=0;j<=n;j++){
c[j][0]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j<w[i]){
c[i][j]=c[i-1][j];
}else
{
c[i][j]=max(c[i-1][j-w[i]]+p[i],c[i-1][j]);
}
}
}
int j=m;
for(int i=n;i>0;i--){
if(c[i][j]>c[i-1][j]){
x[i]=1;
j-=w[i];
}else
{
x[i]=0;
}
}
return c[n][m];
}
int main(){
int n,W;
int we;//总重量
cin>>n;
cin>>we;
for(int i=1;i<=n;i++){
cin>>w[i];
}
for(int i=1;i<=n;i++){
cin>>p[i];
}
int WE=kanpsack_1(n,we);
for(int i=1;i<=n;i++){
cout<<x[i]<<" ";
}
cout<<endl;
cout<<WE<<endl;
return 0;
}
/*
5
10
2 2 6 5 4
6 3 5 4 6
*/
深搜0-1背包:记忆化搜索
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int value[1005];
int valume[1005];
int dp[1005][1005];
int n,v;
int dfs(int index,int c){
int res=0;
if(dp[index][c]>=0)return dp[index][c];
if(index>n)return dp[index][c]=0;
if(c<valume[index]){
res=dfs(index+1,c);
}else{
res=max(dfs(index+1,c),dfs(index+1,c-valume[index])+value[index]);
}
dp[index][c]=res;
return res;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n>>v;
for(int i=1;i<=n;i++){
cin>>value[i];
}
for(int i=1;i<=n;i++){
cin>>valume[i];
}
int sum=dfs(1,v);
cout<<sum<<endl;
}
return 0;
}
非记忆化深搜
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int value[1005];
int valume[1005];
int n,v;
int dfs(int index,int c){
int res=0;
if(index>n)return 0;
if(c<valume[index]){
res=dfs(index+1,c);
}else{
res=max(dfs(index+1,c),dfs(index+1,c-valume[index])+value[index]);
}
return res;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n>>v;
for(int i=1;i<=n;i++){
cin>>value[i];
}
for(int i=1;i<=n;i++){
cin>>valume[i];
}
int sum=dfs(1,v);
cout<<sum<<endl;
}
return 0;
}
二:多重背包:
思路:将多重背包转换为0-1背包。
状态转移方程为 dp[i+1][j]=max(dp[i][j-w[i]*k])+v[k] k=(0…g[i]);g[i]表示物品i共有几个。
方法一:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int W,n;
int w[105],v[105],g[105];
int dp[205][20005];
int main(){
int T;
scanf("%d",&T);
while(T--){
memset(dp,0,sizeof(dp));
scanf("%d%d",&W,&n);
for(int i=0;i<n;i++){
scanf("%d%d%d",&w[i],&v[i],&g[i]);//分别表示物品的重量,价值,这种物品的数量
}
for(int i=0;i<n;i++)
for(int j=0;j<=W;j++){
dp[i+1][j]=dp[i][j];
for(int k=1;k<=g[i];k++)
if(j>=k*w[i]) dp[i+1][j]=max(dp[i+1][j],dp[i][j-w[i]*k]+v[i]*k);
}
printf("%d\n",dp[n][W]);
}
return 0;
}
方法二:转化为01背包
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{
int cost;
int weight;
int nums;
}num[1000005];
int sum_cost,kind;
int dp[1005];
int main(){
int t;
cin>>t;
while(t--){
int cnt=0;
cin>>sum_cost>>kind;
for(int i=1;i<=kind;i++){
int x,y,z;//分别表示物品的重量,价值,这种物品的数量
cin>>x>>y>>z;
for(int j=1;j<=z;j++){
num[cnt].cost=x;
num[cnt++].weight=y;
}
}
for(int i=0;i<cnt;i++){
for(int j=sum_cost;j>=num[i].cost;j--){
dp[j]=max(dp[j],dp[j-num[i].cost]+num[i].weight);
}
}
cout<<dp[sum_cost]<<endl;
}
return 0;
}
方法三:记忆化搜索
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{
int cost;
int weight;
int nums;
}num[105];
int sum_cost,kind;
int dp[105][10005];
int solve(int index,int sumcost){
int temp;
if(dp[index][sumcost]>0)return dp[index][sumcost];
if(index>=kind||sumcost==0)return dp[index][sumcost]=0;
else if(num[index].cost>sumcost){
temp=solve(index+1,sumcost);
}else{
for(int k=0;k<=num[index].nums&&k*num[index].cost<=sumcost;k++){
temp=max(solve(index+1,sumcost),solve(index+1,sumcost-num[index].cost*k)+num[index].weight*k);
}
}
dp[index][sumcost]=temp;
return temp;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>sum_cost>>kind;
for(int i=1;i<=kind;i++){
cin>>num[i].cost>>num[i].weight>>num[i].nums;
}
int sum=solve(1,sum_cost);
cout<<sum<<endl;
}
return 0;
}
方法四:转换为二进制方法
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int W,n;
int w[2005],v[2005];
int dp[20005];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
scanf("%d%d",&W,&n);
int cnt=0;
int a,b,c;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&a,&b,&c);//分别表示物品的重量,价值,这种物品的数量
int e=1;
while(e<c)
{
w[cnt]=a*e;
v[cnt]=b*e;
cnt++;
c-=e;
e*=2;
}
w[cnt]=a*c;
v[cnt]=b*c;
cnt++;
}
for(int i=0;i<cnt;i++)
for(int j=W;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d\n",dp[W]);
}
return 0;
}
三:回溯法求解0-1背包
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxx=105;
const int inf=0x3f3f3f3f;
int w[maxx];//物品的重量
int v[maxx];//物品的价值
int cp;//当前的价值
int cw;//当前的重量
int c;//重量的上限
int bestp;//最后的最大价值
int bestx[maxx];//记录被装入背包的物品
int x[maxx];//记录当前装入背包的物品
int n,m;
void init(){
cw=0;cp=0;;
memset(w,0,sizeof(w));
memset(v,0,sizeof(v));
memset(bestx,0,sizeof(bestx));
}
int Bound(int i){//计算上界 ,存在比当前可能的更优解
int cleft=c-cw;
int b=cp;
while(i<=n&&w[i]<=cleft){
cleft-=w[i];
b+=v[i];
i++;
}
if(i<=n){
b+=v[i]/w[i]*cleft;
}
return b;
}
void BackTrack(int t){
if(t>n){
for(int j=1;j<=n;j++){
bestx[j]=x[j];
}
bestp=cp;
return ;
}
if(cw+w[t]<=c){
x[t]=1;
cw+=w[t];
cp+=v[t];
BackTrack(t+1);//进入左子树
cw-=w[t];
cp-=v[t];
}
if(Bound(t+1)>bestp){//进入右子树
x[t]=0;
BackTrack(t+1);
}
}
int main(){
while(scanf("%d %d",&n,&c)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
}
for(int i=1;i<=n;i++){
scanf("%d",&v[i]);
}
BackTrack(1);
cout<<"最大价值: "<<bestp<<endl;
cout<<"可以被装入的物品: ";
for(int i=1;i<=n;i++){
if(bestx[i]==1){
cout<<i<<" ";
}
}
cout<<endl;
}
return 0;
}
这是我自己在做题中总结出来的,如果存在什么问题或者错误,请指出!谢谢!