本周学习了动态规划,第一次听说动态规划,还是在寒假的时候,那时候我初步接触算法,我的一个同学有一天晚上突然问我,你学到DP了吗?为了不丢人,我连忙从床上爬起来去查啥是DP,才知道这叫动态规划,只是没想到我现在才学这个,我比别人拉下的太多了。。。
目录
动态规划思想解析:
动态规划和贪心的区别:
例题:
<1>最小正字段和
<2>回文字符串
总结:
动态规划思想解析:
先把我从百度上扒下来的定义说一遍(主要是怕解释错了误导别人)
————通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
通俗的讲就叫:大事化小,小事化了;若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。(你也可以用打游戏来理解,你要打大BOSS,就要从打小怪开始,解决完大魔王的部下,你才可以打败大魔王),或者说,你有一本高数作业,你一点没动,可是马上就要交了,怎么办,你需要召唤自己的好兄弟,让他们帮你写点(理想状态,请勿当真),每人都写一点。那自然就可以写完了。
动态规划和贪心的区别:
我在这一部分的学习的时候,发现其实动态规划和贪心还蛮像的,但是查过资料之后发现,两者其实有着不小的差别:动态规划问题中每一个状态一定是由上一个状态推导出来的,在这一点上区别于贪心算法,贪心算法是从局部直接选取最优解,并不依赖于之前计算出来的状态。
例题:
<1>最小正字段和
N个整数组成的序列a[1],a[2],a[3],…,a[n],从中选出一个子序列(a[i],a[i+1],…a[j]),使这个子序列的和>0,并且这个和是所有和>0的子序列中最小的。
例如:4,-1,5,-2,-1,2,6,-2。-1,5,-2,-1,序列和为1,是最小的。
思路:我们发现任意两个前缀和的差都代表了一个子段的和,只要两个前缀和之差比较小,那么他就可能是答案,所有我们要尽可能的找到这样的前缀和, 我们发现只要将前缀和进行排序,相邻两项的差就是最小的。但也要保证组成的了正序的序列。
#includeusing namespace std; #define ll long long const int N = 5e4 + 10; int n, a[N]; ll sum[N]; struct node { int id; ll x; bool operator <(const node b) const { if(x == b.x) return id < b.id; return x < b.x; } }v[N]; int main() { cin >> n; for(int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i], v[i].id = i, v[i].x = sum[i]; sort(v, v + n + 1); ll ans = 1<<30; for(int i = 1; i < n; i++) { if(v[i].id > v[i - 1].id && v[i].x != v[i - 1].x) ans = min(v[i].x - v[i - 1].x, ans); } cout << ans << endl; }
<2>回文字符串
所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba"。当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串。现在要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。
思路:本题可以这样想,如果这个字符串里面已经存在了回文串,那么剩下左边和右边的那些就是不对称的,所以在左边补上右边的字符,右边补上左边的字符,这样就会完整了,所以要补齐的字符数目就是总长度减去串内部的回文串长度,而内部的回文串长度则可以由本串和逆串来求出最长回文子序列,这就是基本的dp问题了
#include#include using namespace std; string fun(string str){ string ans; int len=str.length(); for(int i=len-1;i>=0;i--){ ans.push_back(str[i]); } return ans; } int main(){ int n; cin >>n; for(int i=0;i > str1; string str2=fun(str1);//将str1逆置 int len=str1.length(); int dp[1500][1500]; for(int i=0;i<=len;i++){ dp[i][0]=dp[0][i]=0; } for(int i=1;i<=len;i++){ for(int j=1;j<=len;j++){ if(str1[i-1]==str2[j-1]){ dp[i][j]=dp[i-1][j-1]+1; }else{ dp[i][j]=max(dp[i][j-1],dp[i-1][j]); } } } cout< 总结:
动态规划是我感觉最神奇的解法,它不同于暴力搜索,也不同于一般的贪心,能够以出乎人意料的时间复杂度解决一些问题。不过,动态规划的思维性比较强,必须会设好状态,正确写出状态转移方程,并且能够准确判断有无最优子结构。



