动态规划(dynamic programming)初探:01背包问题及其变形/完全背包问题

一、01背包问题及其变形
 
 
1.未经优化的动归算法:
int volume[1002];   //体积
int value[1002];    //价值
int v;              //volume of the bag
int dp[1002][1002];
        for(i=volume[0];i<=v;i++)
            dp[0][i]=value[0]; 
        for(i=1;i<n;i++){
            for(int j=0;j<=v;j++){
                if(j<volume[i]||dp[i-1][j]>dp[i-1][j-volume[i]]+value[i])
                    dp[i][j]=dp[i-1][j];
                else dp[i][j]=dp[i-1][j-volume[i]]+value[i];
            }
        }
        cout<<dp[n-1][v]<<endl;

2.优化后的动归算法:
int dp[1002];

		for(i=0;i<n;i++){
			for(int j=v;j>=volume[i];j--){
				if(dp[j-volume[i]]+value[i]>dp[j])
					dp[j]=dp[j-volume[i]]+value[i];
			}
		}
		cout<<dp[v]<<endl;
  
  
  • 01背包问题的变形
int dp[1000];
struct BG{
    int h;    //快乐度
    int l;    //持续时间
    int t;    //发起人离校时间
};
bool cmp(BG b1,BG b2){
     return b1.t<b2.t;
}
BG bg[32];
int main(){
    int n,i,j,max;
    while(cin>>n&&n>=0){
        max=0;
        for(i=0;i<n;i++)
            cin>>bg[i].h>>bg[i].l>>bg[i].t;
        sort(bg,bg+n,cmp);   //要先按照发起人离校时间从早到晚排序,因为这里
		                     //的dp数组下标(也就是最晚结束时间)并不是越大对每个bg最有利
		max=bg[n-1].t;       //所有bg最晚结束时间
        for(i=0;i<=max;i++)
            dp[i]=0;
        for(i=0;i<n;i++)
            for(j=bg[i].t;j>=bg[i].l;j--)
                if(dp[j-bg[i].l]+bg[i].h>dp[j])
                    dp[j]=dp[j-bg[i].l]+bg[i].h;   
        int happy=0;
		for(i=0;i<=max;i++)         //和01背包另一个不同的地方,因为01背包的dp数组是递增的,而这里的dp[]不是
		if(dp[i]>happy) 
			happy=dp[i];
        cout<<happy<<endl;
    }
}



二、完全背包问题(需要装满的那类)
http://acm.hdu.edu.cn/showproblem.php?pid=1114
for(i=0;i<=v;i++)
            dp[i]=INF;
        dp[0]=0;
        for(i=0;i<n;i++)
            for(int j=volume[i];j<=v;j++)
                if(dp[j-volume[i]]+value[i]<dp[j])
                    dp[j]=dp[j-volume[i]]+value[i];

三、区别
	前者(01背包)第二层循环必须从后到前(因为每个物品只有一个)
	后者(完全背包第二层循环从前到后可以省去一个循环:for(int k=0;k<v/volume[i];k++)
四、多重背包
http://acm.hdu.edu.cn/showproblem.php?pid=2191
#pragma warning (disable:4786)  
#include<iostream>
#include<stdio.h>
#include<vector> 
using namespace std;
int n,m;
int dp[102];       
int price[102];
int weight[102];
int num[102];
int main(){
    int i,j,k,c,n,m;
    scanf("%d",&c);
    while(c--){
        scanf("%d%d",&n,&m);
        for(i=1;i<=m;i++)
            scanf("%d%d%d",&price[i],&weight[i],&num[i]);
        memset(dp,0,sizeof(dp));
        for(i=1;i<=m;i++){
            for(j=1;j<=num[i];j++)
                for(k=n;k>=price[i];k--){
                    if(dp[k]<dp[k-price[i]]+weight[i])
                        dp[k]=dp[k-price[i]]+weight[i];
                }
        }
        printf("%d\n",dp[n]);
    }       
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值