1. 程式人生 > >區間dp(石子合併and括號匹配)

區間dp(石子合併and括號匹配)

就是把大區間劃分為小區間然後取小區間的最優值

處理石子合併和括號匹配

(1). 石子合併

①.n堆石子,每堆有a[i]個,每次合併兩堆,需要體力為相鄰兩堆石子之和

每次合併最小的兩堆就好了

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<iostream>
  4. #include<cstring>
  5. usingnamespace std;  
  6. int main()  
  7. {  
  8.     int n;  
  9.     int sum;  
  10.     int x[10010];  
  11.     while(cin>>n&&n != 0)  
  12.     {  
  13.         sum = 0;  
  14.         memset(x, 0, sizeof(x));  
  15.         for(int i = 0; i < n; i++)  
  16.             cin>>x[i];  
  17.         sort(x, x+n);  
  18.         for(int i = n-1; i > 0; i--)  
  19.         {  
  20.             x[i-1] = x[i-1] + x[i];  
  21.             sum=(sum % 1000000007 + x[i-1] % 1000000007) % 1000000007;  
  22.         }  
  23.         cout<<sum<<endl;  
  24.     }  
  25.     return 0;  
  26. }  

②.n堆石子直線排列,每堆有a[i]個,每次合併相鄰兩堆,需要體力為相鄰兩堆石子之和

sum[i]是前i堆總的石子個數

狀態方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);

  1. /*for(int i = 0; i < n; i++) 
  2.     dp[i][i]=0;*/
  3. for(int t = 1; t < n; t++)  
  4.     {  
  5.         for(int i = 0; i < n-t; i++)  
  6.         {  
  7.             int
     j = i + t;  
  8.             dp[i][j] = inf;  
  9.             for(int k = i; k < j; k++)  
  10.                 dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);  
  11.         }  
  12.     }  

樸素演算法

  1. #include<cstdio>
  2. #include<iostream>
  3. usingnamespace std;  
  4. #define inf 0xffffff
  5. int main()  
  6. {  
  7.     int n;  
  8.     int a[210];  
  9.     int sum[210];  
  10.     int dp[210][210];  
  11.     scanf("%d",&n);  
  12.     for(int i = 0; i < n; i++)  
  13.     {  
  14.         scanf("%d", &a[i]);  
  15.         sum[i]=sum[i-1] + a[i];  
  16.     }  
  17.     for(int i = 0; i < n; i++)  
  18.         dp[i][i] = 0;  
  19. for(int t = 1; t < n; t++)  
  20.     {  
  21.         for(int i = 0; i < n-t; i++)  
  22.         {  
  23.             int j = i + t;  
  24.             dp[i][j] = inf;  
  25.             for(int k = i; k < j; k++)  
  26.                 dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j] + sum[j] - sum[i-1]);  
  27.         }  
  28.     }  
  29.     printf("%d", dp[0][n-1]);  
  30.     return 0;  
  31. }  

這個時間複雜度......o(n^3)

四邊形不等式優化

  1. /*for(int i=1; i<=n; i++)   
  2.     {   
  3.         dp[i][i] = 0;   
  4.         p[i][i] = i;   
  5.     }  */
  6.     for(int len=1; len<n; len++)    
  7.     {    
  8.         for(int i=1; i+len<=n; i++)    
  9.         {    
  10.             int end = i+len;    
  11.             int tmp = INF;    
  12.             int k = 0;    
  13.             for(int j=p[i][end-1]; j<=p[i+1][end]; j++)    
  14.             {    
  15.                 if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)    
  16.                 {    
  17.                     tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];    
  18.                     k = j;  //找到令dp最小的k記下來
  19.                 }    
  20.             }    
  21.             dp[i][end] = tmp;    
  22.             p[i][end] = k;    
  23.         }    
  24.     }    

ac程式碼

  1. #include<cstdio>
  2. #include<iostream>
  3. usingnamespace std;  
  4. #define inf 0xffffff
  5. int main()  
  6. {  
  7.     int n;  
  8.     int a[210];  
  9.     int sum[210];  
  10.     int dp[210][210];  
  11.     int p[210][210];  
  12.     scanf("%d",&n);  
  13.     for(int i = 1; i <= n; i++)  
  14.     {  
  15.         scanf("%d", &a[i]);  
  16.         sum[i]=sum[i-1] + a[i];  
  17.     }  
  18. for(int i=1; i<=n; i++)  
  19.     {  
  20.         dp[i][i] = 0;  
  21.         p[i][i] = i;  
  22.     }  
  23.     for(int len=1; len<n; len++)  
  24.     {  
  25.         for(int i=1; i+len<=n; i++)  
  26.         {  
  27.             int end = i+len;  
  28.             int tmp = inf;  
  29.             int k = 0;  
  30.             for(int j=p[i][end-1]; j<=p[i+1][end]; j++)  
  31.             {  
  32.                 if(dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1] < tmp)  
  33.                 {  
  34.                     tmp = dp[i][j] + dp[j+1][end] + sum[end] - sum[i-1];  
  35.                     k = j;    
  36.                 }  
  37.             }  
  38.             dp[i][end] = tmp;  
  39.             p[i][end] = k;  
  40.         }  
  41.     }  
  42.     printf("%d", dp[1][n]);  
  43.     return 0;  
  44. }  

時間複雜度大概為o(n^2)了

完了以後GarsiaWachs演算法

哇咔咔妙哇

存stone[ ]陣列,從左往右,找一個k滿足stone[k-1] <= stone[k+1],完了以後合併stone[k]和stone[k-1],再從當前位置開始向左找最大的j,使其滿足stone[j] > stone[k]+stone[k-1],插到j的後面。重複,直到只剩下一堆石子......假設stone[-1]和stone[n]是正無窮的

ac程式碼

  1. #include <cstdio>
  2. #include <iostream>
  3. usingnamespace std;  
  4. int stone[205];  
  5. int n,t,ans;  
  6. void combine(int k)  
  7. {  
  8.     int tmp = stone[k] + stone[k-1];  
  9.     ans += tmp;  
  10.     for(int

    相關推薦

    區間dp石子合併and括號匹配

    就是把大區間劃分為小區間然後取小區間的最優值處理石子合併和括號匹配(1). 石子合併①.n堆石子,每堆有a[i]個,每次合併兩堆,需要體力為相鄰兩堆石子之和每次合併最小的兩堆就好了#include<cstdio>#include<algorithm>#

    區間dp模型石子歸併,括號匹配,整數劃分

    區間dp顧名思義就是在一個區間上進行的一系列動態規劃。對一些經典的區間dp總結在這裡。 1) 石子歸併問題 描述:有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過

    【模板題】動態規劃 石子合併括號匹配、加分二叉樹——區間dp問題及其整理

    題目大意:輸入一棵樹的中序遍歷,定義一棵子樹的得分為其左子樹的加分×右子樹的加分+根的分數。求最大得分及先序遍歷注意:1、初始化r[i][i]=i,便於輸出2、初始化dp[i][i-1]=dp[i+1][i]=1。因為在區間中選取一點為root時會取到端點,即左(右)子樹為空

    牛客國慶集訓派對Day1 J-Princess Principal 區間查詢是否是正確的括號匹配

    阿爾比恩王國(the Albion Kingdom)潛伏著一群代號“白鴿隊(Team White Pigeon)”的間諜。在沒有任務的時候,她們會進行各種各樣的訓練,比如快速判斷一個文件有沒有語法錯誤,這有助於她們鑑別寫文件的人受教育程度。 這次用於訓練的是一個含有n個括

    【tyvj】【區間dp石子合併

    【問題描述】 在一個操場上擺放著一行共n堆的石子。現要將石子有序地合併成一堆。規定每次只能選相鄰的兩堆合併成新的一堆,並將新的一堆石子數記為該次合併的得分。請編輯計算出將n堆石子合併成一堆的最小得分和將n堆石子合併成一堆的最大得分。 【輸入檔案】 輸入

    poj1179 區間dp記憶化搜索寫法有巨坑!

    edge one string.h return remove 表達 分享 div center http://poj.org/problem?id=1179 Description Polygon is a game for one player th

    LeetCode 20 Valid Parentheses用棧判斷括號匹配

    Given a string containing just the characters'(',')','{','}','['and']', determine if the input str

    POJ2955BRACKETS區間DP括號匹配

    ongl unity jvm wss lfa 匹配 區間 ack .com %E7%94%A8UNITY5%E5%BC%80%E5%8F%91%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%89%8B%E6%9C%BA%E6%B8%B8%E6%88%8F%28

    POJ2955 Brackets區間DP括號匹配

    POJ2955 首先考慮怎麼樣定義dp讓它滿足具有通過子結構來求解、 定義dp [ i ] [ j ] 為串中第 i 個到第 j 個括號的最大匹配數目 那麼我們假如知道了 i 到 j 區間的最大匹

    Brackets區間dp括號匹配

    We give the following inductive definition of a “regular brackets” sequence: the empty sequence is a regular brackets sequence,if s is a regular brackets

    區間dp學習篇括號匹配

    括號匹配,根據題目要求求解最大括號匹配數 比如這道題,和石子合併不同的是,題目給定的括號匹配情況需要我們自己更新,不像石子合併中給定數值來的直接,這就需要我們在之前的狀態轉移方程(dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j

    POJ2955區間括號匹配

    普通寫法 #include<iostream> #include<cmath> #include<cstdio> #include<cstdlib>

    四邊形不等式dp優化應用及證明石子合併n^2

    石子合併是一道很經典的區間動規。 在n^3的暴力裡面,我們的狀態轉移方程是: f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+w[i][j])f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+w[i]

    區間dp整數劃分,石子劃分

    整數劃分(四) 基礎區間dp,程式碼: #include <cstdio> #include <cstring> long long a[20][20]; long lon

    leetcode_棧的應用括號匹配

    20. 有效的括號 給定一個只包括 '(',')','{','}','[',']' 的字串,判斷字串是否有效。 有效字串需滿足: 左括號必須用相同型別的右括號閉合。 左括號必須以正確的順序閉合。 注意空字串可被認為

    C/C++ 泛型程式設計stack括號匹配

    題目描述 假設表示式中包含一種括號:圓括號,其巢狀順序隨意,即(()())或(())等為正確的格式,)(或((())或())均為不正確的格式。檢驗括號是否匹配可以用堆疊來實現當遇到 ( 時進棧,遇到 ) 時出棧進行匹配檢驗,如果出現不匹配的情況立即結束,否則繼續取下一個字元

    資料結構篇:鏈棧應用括號匹配C++

    很簡單,掌握棧的基礎知識即可。 #include <iostream> #include <string.h> using namespace std; struct Node { int data; Node *next; }; class

    牛客國慶集訓派對Day1 J Princess Principal線段樹+括號匹配

    隊友寫的一個線段樹加字首的東西 太強了 #include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> usin

    資料結構與演算法 -- 棧的應用進位制轉換、括號匹配

    棧的應用 ps:用棧很簡單實現的應用有很多,比如說進位制轉換,括號匹配等。學計算機的都知道,2進位制,8進位制,10進位制,16進位制等,進位制之間的轉換也是需要掌握的,以備不時之需,所以我們可以自己寫一段程式如果會android的話,可以直接打包成APK。下面就按照這兩個應用稍微寫一點C語言的程式碼。 進

    leetcode-20:Valid Parentheses有效的括號括號匹配

    題目: Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the