coding
1.如此编码 纯数学模拟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> #include <vector> using namespace std;int main () { int n , m ; vector<int > a (n+1 ) ,b (n+1 ) ; vector<long > c (n+1 ) ; cin>>n>>m; for (int i=1 ;i<=n;i++){ cin>>a[i]; } c[0 ] = 1 ; long long flag = 1 ; for (int i=1 ;i<=n;i++){ c[i]=flag*a[i]; flag = c[i]; } for (int i=n;i>=1 ;i--){ b[i]=m/c[i-1 ]; m = m%c[i-1 ]; } for (int i=1 ;i<=n;i++){ cout<<b[i]<<" " ; } return 0 ; }
2.何以包邮? 本质是稍作改动的 01背包问题 ,先复习(预习)下。
背包基础
有 件物品和一个容量为 的背包。放入第i 件物品花费的费用是 ,得到的价值是 ,求将哪些物品装入背包可使价值总和最大。(这里的费用可理解为将某个物品装入背包所付出的空间上的代价, 可视作cost, 可视作worth,下面的代码统一用这两个变量表示费用和价值)
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态: 表示前 件物品恰 放入一个容量为 的背包可获得的最大价值。实际上不需要正好装满,初始化可以分开这两种情况,如下是状态转移方程:
如果不放第 件物品,问题转化为 前 件物品放入容量为 的背包中,最大价值为 ;
如果放第 件物品,问题转化为 前 件物品放入剩下容量为 的背包中,再加上放第 件物品的价值,此时能获得的最大价值就是 。
优化空间复杂度 1 2 3 for (int i = 1 ; i <= n; i++) for (int j = 1 ; j <= v; j--) f[j] = max (f[j], f[j - c[i]] + w[i]);
学习只用一维数组解01背包问题是十分必要的,尤其在完全背包问题中,后续会详细讲解。
初始化细节 有的题目要求”恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。这两种问法的区别是在初始化的时候有所不同。
①要求恰好装满背包:
为 ,其余为 , 分别对应恰好装满容量为 的背包的最优解。
初始化的 数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为 的背包可能被价值为 的 nothing “恰好装满”,其它容量 的背包均没有合法的解 ,属于未定义的状态,它们的值就都应该是 了。
②没有要求必须把背包装满,而是只希望所装物品价值尽量大:
全部设为 。
如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为 ,所以初始时状态的值也就全部为 了。
模板题目 AC Wing 01背包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> #include <algorithm> #define MAXN 1005 int n , m ; int v[MAXN] ;int w[MAXN] ;int f[MAXN][MAXN] ;using namespace std ;int main (int argc,char ** argv) { cin>>n>>m ; for (int i=1 ; i<=n; i++) cin>>v[i]>>w[i] ; for (int i=1 ; i<=n; i++){ for (int j=1 ; j<=m; j++){ if (j<v[i]) f[i][j] = f[i-1 ][j] ; else { f[i][j] = max (f[i-1 ][j],f[i-1 ][j-v[i]]+w[i]) ; } } } cout<< f[n][m] <<endl ; return 0 ; }
洛谷干草出售
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <algorithm> #define MAXN 50005 int c,h ; int v[MAXN] ; int f[MAXN] ;using namespace std ;int main (int argc,char ** argv) { cin>>c>>h ; for (int i=1 ; i<=h; i++) cin>>v[i] ; for (int i=1 ; i<=h; i++){ for (int j=c; j>=v[i]; j--){ f[j] = max (f[j],f[j-v[i]]+v[i]) ; } } cout<<f[c]<<endl; return 0 ; }
洛谷疯狂地采药
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <algorithm> #define MAXN 50005 int c,h ; int v[MAXN] ; int f[MAXN] ;using namespace std ;int main (int argc,char ** argv) { cin>>c>>h ; for (int i=1 ; i<=h; i++) cin>>v[i] ; for (int i=1 ; i<=h; i++){ for (int j=c; j>=v[i]; j--){ f[j] = max (f[j],f[j-v[i]]+v[i]) ; } } cout<<f[c]<<endl; return 0 ; }
202209-2 何以包邮?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #define MAXN 600000 using namespace std ;int n,x ;int a[MAXN] ;int f[MAXN];main (int argc,char ** argv){ int sum = 0 ; cin>>n>>x ; for (int i=1 ;i<=n;i++){ cin>>a[i] ; sum += a[i] ; } int y = sum - x ; for (int i=1 ; i<=n; i++){ for (int j=y; j>=a[i]; j--){ f[j] = max (f[j],f[j-a[i]]+a[i]); } } int ans = sum -f[y] ; cout<< ans <<endl; return 0 ; }