动态规划和背包dp问题
来源:互联网 发布:去除淘宝店铺模块缝隙 编辑:程序博客网 时间:2024/06/05 14:30
10.3(第一天):
今天是国庆节假期的第三天了,回顾开学来这近一个月,可用两字概括:迷茫。
野心勃勃地想要飞速提升自我,却因每天的课程安排而无法挪出长时间段自行学习,又不满足于仅听课学习。
选了英语写作课和口语课,突觉以前自己引以为豪的英语其实比起同龄人来说落后不止一点,之前的六级成绩也让我有些失落(但并未觉得很难受,不知是积极乐观还是好强心磨灭的体现)。
想要尽快找到能让自己感到骄傲的东西,把念头转向自己的专业,报名蓝桥杯,希望自己能冲个国奖,保研到理想学校去。
但我是算法小白,我必须超前努力。
因为高考失利,我反思到自己的所谓“踏实”其实是没有自己想法、方法地死读书,缺少灵活安排时间和专注学习的能力和毅力。
焦虑的我,在国庆假期第三天,打开b站,没有再搜游戏视频,反而一念之间搜了“算法”,发现有自己高考填志愿在海大之前却连调档线都没能上的杭电,和高考后望尘莫及的电子科大,它们都有oj,而正有两个人在b站上开视频在讲oj上的部分算法题。
我知道,这些视频,是我算法之路的开始。
我打算:只要有空闲时间就去图书馆安排看视频学习,学了是一定要在这来码一遍做好笔记的,周一周二的水晚课就下载视频到手机里离线看(回来再补笔记)。每天搞懂一个算法,做懂例题并码好,我相信终有一日成大牛。
持续21天,据说可以成为习惯,你试一试呢。
我必须让自己感到“不舒适”,而不要去在意他人的眼光。我就是我,我要走出我勤勉、坚持的算法之路。
【动态规划 DP】:
1.数塔问题
#include <stdio.h>#include <bits/stdc++.h>#include <algorithm>
using namespace std;int main(){int t,n,dp[105][105],a[105][105]; //dp用来储存结果,a来代表该格子的数 scanf("%d",&t); //待测实例数while(t--) {scanf("%d",&n); //该实例中有几层for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)scanf("%d",a[i][j]); //输入每层的数据}memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++)dp[n][i]=a[n][i]; //最后一层的dp就是自己的值for(int i=n-1;i>=1;i--) //注意!要自底向上,用数组储存。 for(int j=1;j<=i;j++) dp[i][j]=max(dp[i+1][j],dp[i+1][j+1]); return 0;}
2.馅饼问题
#include <stdio.h>#include <bits/stdc++.h>#include <algorithm>using namespace std;int main(){int n,m,x,t,dp[10005][13]; //n是共有n个馅饼掉下来,m记录最多是掉了多少秒,x是位置,t是掉落时间点,dp是共接馅饼数。while(--scanf("%d",&n)&&n){memset(dp,0,sizeof(dp));m=0;while(n--){scanf("&d&d",&x,&t)if(t>m) m=t;dp[t][x]++ //先把这些点掉来的馅饼数初始化好。}}for(int i=m-1;i>=1;i--)for(int j=0;j<=10;j++)dp[i][j]=max(max(dp[i+1][j-1],dp[i+1][j]),dp[i+1][j+1]); //用dp,同理倒推,此时的i为开始计算dp的时间节点}printf("%d\n",dp[0][5]);}
#include <stdio.h>#include <bits/stdc++.h>#include <algorithm>using namespace std;const int maxn=205;int n,m;int mp[maxn][maxn];int main(){while(scanf("%d%d",&n,&m)!=EOF){for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(i==j) mp[i][j]==0;else mp[i][j]=1e6; //先初始化mp 把不同道路间距离整成很远的一个数}for(int i=1;i<=m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);mp[x][y]=z;mp[y][x]=z;}int s,t;scanf("%d%d",&s,&t);for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);if(mp[s][t]==1e6) cout<<"-1"<<endl;else cout<<mp[s][t]<<endl;}
动态规划(DP算法)学习心得:
我觉得吧,这种题型有些共同点:都是求max和min的,而且每一步的选择都会影响结果,那么选择从底向上(逆推)即“递推的简化——数组存储”。当然要注意把边界值(初始值)先设好。
但我觉得难在要根据题目所给的“输入要求”设计,好吧好像也没有很难。。只要把题读懂了,把一些变量设好就还好。
递归到动规的一般转化方法
递归函数有n个参数,就定义一个n维的数组,数组的下标是递归函数参数的取值范围,数组元素的值是递归函数的返回值,这样就可以从边界值开始, 逐步填充数组,相当于计算递归函数值的逆过程。
动规解题的一般思路
1. 将原问题分解为子问题
- 把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。子问题都解决,原问题即解决(数字三角形例)。
- 子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。
2.确定状态
- 在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
- 所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在数字三角形的例子里,一共有N×(N+1)/2个数字,所以这个问题的状态空间里一共就有N×(N+1)/2个状态。
整个问题的时间复杂度是状态数目乘以计算每个状态所需时间。在数字三角形里每个“状态”只需要经过一次,且在每个状态上作计算所花的时间都是和N无关的常数。
3.确定一些初始状态(边界状态)的值
以“数字三角形”为例,初始状态就是底边数字,值就是底边数字值。
4. 确定状态转移方程
定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推型)。状态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方程”。
数字三角形的状态转移方程:
能用动规解决的问题的特点
1)问题具有最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质。
这一点强烈明显地体现在背包问题中。
2) 无后效性。当前的若干个状态值一旦确定,则此后过程的演变就只和这若干个状态的值有关,和之前是采取哪种手段或经过哪条路径演变到当前的这若干个状态,没有关系。
10.4(第二天):
title: 饭卡 杭电oj 2546
tags: [动态规划]
题目链接
Problem Description
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
Input
多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。
Output
对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
Sample Input
1505101 2 3 2 1 1 2 3 2 1500
Sample Output
-4532
分析:
本题就是01背包dp问题。不过要用sort排序,以把最贵的东西最后买(由题意,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负))。
解题代码:
#include <bits/stdc++.h>using namespace std;int main(){int n,V,w[1005],dp[1005];while(cin>>n && n){memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++) cin>>w[i];cin>>V;sort(w,w+1+n);if(V<5) cout<<V<<endl;else{for(int i=1;i<=n;i++){ for(int j=V-5;j>=w[i];j--){ dp[j]=max(dp[j],dp[j-w[i]]+w[i]); }}cout<<V-dp[V-5]-w[n]<<endl;}} return 0;}
注意:01背包若用一维数组解题,空间V的for循环中要逆序循环,因为dp[i]取决因素其实是(用二维数组书写)dp[i-1][j]和dp[i-1][j-w[i]]+w[i],而明显,dp[i-1][j-w[i]]在一维中表示为dp[j-w[i]],即:这次装东西必须要看上次装(上一个)东西时的最优决策。若 V正序,则会把在(i-1)循环时赋好的这个值给修改掉,不行!所以要逆序。
然而,完全背包的V的for循环要正序循环,原因是因为它装同一个东西可以装无限次你知道吗,所以这次装东西可以取决于上次装(同一)东西的最优决策!
然后,需要理解下面的图(初始化细节):
而怎么设无穷呢?
好,那接下来看看完全背包问题:
二.装硬币问题(杭电1114
题意:已知空罐重量、当前重量、每种硬币的重量和面值,要求根据给定的储钱罐重量求出储钱罐内至少含有多少钱。
思路:要求恰好装满的完全背包(求最小值)
#include<bits/stdc++.h>using namespace std;const int INF = 0x3f3f3f3f;const int maxn=1e5;int main(){int t,e,f,n; //t是共有几组待测case,e是空罐重量,f是满罐重量,n是硬币种类数。scanf("%d",&t);while(t--) {scanf("%d%d",&e,&f);scanf("%d",&n);int dp[maxn];dp[0]=0;for(int i=1;i<=maxn;i++){dp[i]=INF;}for(int i=1;i<=n;i++){int weight,value; //不用整数组了,因为无限次用当前种类,与前无关。 scanf("%d%d",&weight,&value);for(int j=weight;j<=f-e ;j++) //完全背包,j从weight到背包最大容量顺序循环 dp[j]=min(dp[j],dp[j-weight]+value); }if(dp[f-e]==INF) printf("This is impossible.\n");else printf("The minimum amount of money in the piggy-bank is 100.\n");}return 0;}
【多重背包】:即每个种类的物品是有限个数!其实就是多加一层循环!
三。杭电oj2191
#include<bits/stdc++.h>using namespace std;int main(){int C,n,m,dp[105];int value[105],weight[105],bag[105];scanf("%d",&C);while(C--){memset(dp,0,sizeof(dp));scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){cin>>value[i]>>weight[i]>>bag[i]; //分成3个数组, 各自存储不同的属性!!!!for(int k=1;k<=bag[i];k++) for(int j=n;j>=value[i];j--) //要倒序,因为我想用的是装(同种类)装上一个物品时的dp[j]和dp[j-value[i]],不便给它先改了 dp[j]=max(dp[j],dp[j-value[i]]+weight[i]); }cout<<dp[n]<<endl;} return 0;}
- 动态规划和背包dp问题
- 【动态规划】背包问题 - dp
- DP(动态规划)背包问题
- 01背包问题(动态规划DP)
- 01背包问题--dp动态规划
- 01背包问题(动态规划DP)
- 夕拾算法进阶篇:17)01背包和完全背包问题 (动态规划DP)
- 背包问题 动态规划和回溯算法
- 背包问题:动态规划和贪心算法
- 背包问题:贪心和动态规划
- 动态规划 背包问题
- 【动态规划】背包问题
- 动态规划-背包问题
- 动态规划+背包问题
- 动态规划-背包问题
- 背包问题 -- 动态规划
- 《背包问题》 动态规划
- 动态规划-背包问题
- Dubbo框架的搭建以及入门案例
- 使用 Arrays 类操作 Java 中的数组
- chrome浏览器访问google的方法
- C++从入门到放弃之 函数指针
- pycharm pip源修改以及包管理
- 动态规划和背包dp问题
- 大型高性能ASP.NET系统架构设计
- Python网络爬虫与信息提取(二):网络爬虫之提取
- OpenCV-Python—图像平滑和模糊
- 《她身之欲》(珠三角阅流动人口社群特殊职业研究)阅读感想
- leetcode Min Stack 最小栈
- IAR Embebdded Workbench IDE转移设置到另一部电脑中
- Hibernate与spring整合不能建表的问题
- (crm笔记)阶段一总结