動態規劃

 

最長連續子數列和

-2 6 -1 5 4 -7 2 3html

求連續的子數列最大和。ios

根據遞歸的思路想:f(n) = max{ f(n-1) + num[n], num[n] }web

 

 

hdu1506 Largest Rectangle in a Histogram

對於每個高度h[i],搜索它能到達的最左,和最右,最大面積Smax = Max{ i | 面積Si = (最右 - 最左 + 1) *h[i] }數組

這樣的時間複雜度爲O(n^2),必超時ide

舉例 2,3,4,5ui

要判斷2能到達最右的位置,不須要循環比較,只須要知道3能到達的最右是哪裏,由於若3能到達的位置,2必然也能到達spa

 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\n",ans);
37     }
38 }
View Code

 

LeetCode 338. Counting Bits

第一道本身作出來的DP!!!記念合影,你沒聽錯我就是這麼菜3d

給你一個非負整數num,求從0到num的num+1個數中,每一個數二進制表示的1的個數,返回一個數組code

就是dp嘛,暴力的辦法就是for from 0 to num,每一個數的每個二進制位比較,設二進制位最壞長度爲31位,那麼複雜度就是O(31*n)htm

其中大量重複計算,因此用動態規劃解決,自底向上

 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 };
View Code

 

非連續最大子集

給你一個序列arr = {}

請你求出它的一個子集,要求,子集和最大,且子集的元素在原序列終不能相鄰

入門DP

對於每個數,dp[i] = max{ dp[i-1], dp[i] + arr[i-1] }

那麼就和斐波那契有點像了

 

能不能組成S?

給你一個序列arr = {},和一個數S,問你序列裏的數能不能組成S

又是簡單的選和不選問題

 

 

web數據挖掘中的編輯距離

這個有點難想,參考連接

 

稍微變了一小下的01揹包

uim拉着基友小A到了一家……餐館,很低端的那種。

uim指着牆上的價目表說:「隨便點」。

題目描述

不過uim因爲買了一些,口袋裏只剩M元(M10000)。

餐館雖低端,可是菜品種類很多,有N(N100),第i種賣a(ai1000)。因爲是很低端的餐館,因此每種菜只有一份。

小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\n", dp[n][m]);
View Code
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息