• 一本通1267:【例9.11】01背包问题 (浅谈01背包问题)


    原题传送门

    一道01背包入门 & 模板题,以下主要提供两种思路

    (Solution 1)

    看到这道题,首先想到的就是用二维数组来(DP)

    状态的表示:(f[i][j])表示前(i)个总重量不超过(j)的最大价值

    状态的转移:(f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]) (w[i]<=j))
    注:(w[i])表示第(i)个物品的重量,(c[i])表示第(i)个物品的价值,(j)表示当前的最大重量

    最优解:(f[n][m])
    注:(n)指物体数量,(m)指最大重量

    (Code)

    #include<iostream>
    #include<cstdio>
    #include<string>
    using namespace std;
    inline void read(int &x){
    	int f=1;
    	char ch=getchar();
    	x=0;
    	while(ch<'0'||ch>'9'){
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9'){
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	x*=f;
    }
    int m,n;
    int f[201][201]={0};
    int w[31],c[31];
    int main(){
    	read(m);read(n);
    	for(int i=1;i<=n;i++){
    		read(w[i]);
    		read(c[i]);
    	}
    	for(int i=1;i<=n;i++){      //当前物体编号
    		for(int j=m;j>0;j--){      //当前最大重量
    			if(w[i]<=j) f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
    			else f[i][j]=f[i-1][j];
    		}
    	}
    	printf("%d",f[n][m]);
    	return 0;
    }
    

    (Solution 2)

    显然,二维数组的空间占用非常大。如果背包的最大空间再大一些,就会喜提(MLE)的好成绩

    那就有一种新的方法:

    状态的表示:(f[j])表示不超过(j)重量的最大价值

    状态的转移:(f[j]=max(f[j],f[j-w[i]]+c[i]))
    注:(i)依然表示物品编号

    最优解:(f[m])
    注:(m)表示最大重量

    (Code)

    #include<iostream>
    #include<cstdio>
    #include<string>
    using namespace std;
    inline void read(int &x){
    	int f=1;
    	char ch=getchar();
    	x=0;
    	while(ch<'0'||ch>'9'){
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9'){
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	x*=f;
    }
    #include<iostream>
    #include<cstdio>
    #include<string>
    using namespace std;
    inline void read(int &x){
    	int f=1;
    	char ch=getchar();
    	x=0;
    	while(ch<'0'||ch>'9'){
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9'){
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	x*=f;
    }
    int m,n;
    int f[201]={0};
    int w[31],c[31];
    int main(){
    	read(m);read(n);
    	for(int i=1;i<=n;i++){
    		read(w[i]);
    		read(c[i]);
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=m;j>=w[i];j--){	//j>=w[i]保证一定能装下
    			f[j]=max(f[j],f[j-w[i]]+c[i]); 
    		}
    	}
    	printf("%d",f[m]);
    	return 0;
    }
    

    看到最后,可能会有一个问题:为什么需要倒序循环?
    观察状态转移方程:(f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]) (w[i]<=j))
    (f[i][j])的值只与上一行的值(f[i-1][])有关
    更新的时候需要用到旧值,倒序防止循环被覆盖。

  • 相关阅读:
    js-封装几个常用函数
    js获取地址栏的几种方法
    vue 子组件传值给父组件,兄弟组件传参以及实现动态组件
    实现同一个组件页面通过不同的tab标签页打开
    echarts柱状图一组数不同柱子的颜色修改
    echarts实现环形图
    vue 中JSONPath的使用方法之一
    vue element-ui 左侧菜单栏 el-menu属性实现动态菜单
    vue 前端服务器代理,proxyTable简要叙述
    分享一篇IBN(Intent-based networking)调研报告
  • 原文地址:https://www.cnblogs.com/-pwl/p/13731201.html
Copyright © 2020-2023  润新知