最长连续子数列和
-2 6 -1 5 4 -7 2 3
求连续的子数列最大和。
根据递归的思路想:f(n) = max{ f(n-1) + num[n], num[n] }
hdu1506 Largest Rectangle in a Histogram
对于每一个高度h[i],搜索它能到达的最左,和最右,最大面积Smax = Max{ i | 面积Si = (最右 - 最左 + 1) *h[i] }
这样的时间复杂度为O(n^2),必超时
举例 2,3,4,5
要判断2能到达最右的位置,不需要循环比较,只需要知道3能到达的最右是哪里,因为若3能到达的位置,2必然也能到达
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 5 int main() 6 { 7 int n; 8 while(scanf("%d", &n) && n) 9 { 10 long long h[100007]; 11 long long l[100007]; 12 long long r[100007]; 13 for(int i=1;i<=n;i++) 14 { 15 scanf("%lld", &h[i]); 16 l[i] = r[i] = i; 17 } 18 h[0] = h[n+1] = -1; 19 for(int i=1;i<=n;i++) 20 { 21 while(h[i] <= h[l[i]-1]) { 22 l[i] = l[l[i]-1]; 23 } 24 } 25 for(int i=n;i>=1;i--) 26 { 27 while(h[i] <= h[r[i]+1]) { 28 r[i] = r[r[i]+1]; 29 } 30 } 31 long long ans = 0; 32 for(int i=1;i<=n;i++) 33 { 34 ans = ans > (r[i]-l[i]+1)*h[i] ? ans : (r[i]-l[i]+1)*h[i]; 35 } 36 printf("%lld ",ans); 37 } 38 }
LeetCode 338. Counting Bits
第一道自己做出来的DP!!!纪念合影,你没听错我就是这么菜
给你一个非负整数num,求从0到num的num+1个数中,每个数二进制表示的1的个数,返回一个数组
就是dp嘛,暴力的办法就是for from 0 to num,每个数的每一个二进制位比较,设二进制位最坏长度为31位,那么复杂度就是O(31*n)
其中大量重复计算,所以用动态规划解决,自底向上
1 class Solution { 2 public: 3 vector<int> countBits(int num) { 4 vector<int>dp(num+1); 5 dp.resize(num+1); 6 dp[0] = 0; 7 for(int i=1;i<=num;i++) 8 { 9 if((i & 1) == 0) 10 dp[i] = dp[i>>1]; 11 else 12 dp[i] = dp[i>>1] + 1; 13 } 14 return dp; 15 } 16 };
非连续最大子集
给你一个序列arr = {}
请你求出它的一个子集,要求,子集和最大,且子集的元素在原序列终不能相邻
入门DP
对于每一个数,dp[i] = max{ dp[i-1], dp[i] + arr[i-1] }
那么就和斐波那契有点像了
能不能组成S?
给你一个序列arr = {},和一个数S,问你序列里的数能不能组成S
又是简单的选和不选问题
web数据挖掘中的编辑距离
这个有点难想,参考链接:
稍微变了一小下的01背包
uim
拉着基友小A
到了一家……餐馆,很低端的那种。
uim
指着墙上的价目表说:“随便点”。
题目描述
不过uim
由于买了一些书
,口袋里只剩M元(M≤10000)。
餐馆虽低端,但是菜品种类不少,有N种(N≤100),第i种卖a元(ai≤1000)。由于是很低端的餐馆,所以每种菜只有一份。
小A
奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim
身上所有钱花完。他想知道有多少种点菜方法。
思路:和裸的价值+容量的01背包不同,原来是求可放入背包且价值最大化,这个是必须装满背包,求有多少种方案。
根据题意设数组dp[i][j]为前i种菜品恰好花费j元的点菜方法数。那么,考虑第i种菜点或不点,若不点,则说明前i-1种菜,已经恰好花费j元;若点,则说明前i-1种菜,花费j-ai元,这样,在点完第i种菜后,恰好花费j元。
因此容易得出公式
dp[i][j] = dp[i-1][j] + dp[i-1][j-ai]
然而很多人想到这里以后就不知道接下来怎么做了。(比如说我)
但是在看到"j - ai"后,应该能想到,对j - ai的情况进行枚举。
若j > ai,则和上式一样。
若j < ai,则说明第i道菜,压根就买不起,因此dp[i][j] = dp[i-1][j]。
若j == ai,那么说明可以只点这一道菜作为一种新的方案,dp[i][j] = dp[i-1][j] + 1。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 using namespace std; 5 6 int dp[103][10003] = {0}; 7 int price[103]; 8 9 int main() 10 { 11 int n, m; 12 scanf("%d%d", &n, &m); 13 for(int i=1;i<=n;i++) { 14 scanf("%d", &price[i]); 15 } 16 for(int i=1;i<=n;i++) { 17 for(int j=1;j<=m;j++) { 18 if (j == price[i]) 19 dp[i][j] = dp[i-1][j] + 1; 20 else if (j > price[i]) 21 dp[i][j] = dp[i-1][j] + dp[i-1][j - price[i]]; 22 else 23 dp[i][j] = dp[i-1][j]; 24 } 25 } 26 printf("%d ", dp[n][m]);