日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

区间dp小结

發布時間:2025/3/16 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 区间dp小结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

區間dp,顧名思義,就是在區間上dp,即把整個區間劃分為一個個的小區間,在小區間內dp求出最優值,然后把這些小區間合并以后就是整個取件的最優值。

下面是一些比較經典的區間dp題目:

1.NYOJ 737 石子合并:http://acm.nyist.net/JudgeOnline/problem.php?pid=737

題意:有n堆石子,每堆有a[i]個,每次合并時只能合并相鄰的兩堆,代價為兩堆石子的個數之和。問把這n堆石子合并成一堆需要的最小代價是多少。

狀態:dp[i][j] 表示合并第 i 堆到第 j 堆石子的最小代價

轉移方程;dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);

其中sum[i]表示前i堆石子的總個數。

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 0x3fffffff const int N = 205; int a[N], sum[N], dp[N][N];int main() {int n, i, j;while(~scanf("%d",&n) && n) {sum[0] = 0;for(i = 1; i <= n; i++) {scanf("%d",&a[i]);dp[i][i] = 0;sum[i] = sum[i-1] + a[i];}for(int l = 2; l <= n; l++) { //枚舉合并的堆數for(i = 1; i <= n - l + 1; i++) { //枚舉起始點j = i + l - 1;dp[i][j] = INF;for(int k = i; k <= j; k++) //枚舉中間分隔點dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);}}printf("%d\n",dp[1][n]);}return 0; }


2.POJ 2955 Brackets?http://poj.org/problem?id=2955

題意:給出一串由‘(‘,’)‘,’[',‘]’組成的字符串,問最多有多少個括號匹配。

狀態:dp[i][j]表示 i 到 j 最多的匹配個數

轉移方程:dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j]);

#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int N = 105; char str[N]; int dp[N][N]; bool judge(char a, char b) {if(a == '(' && b == ')') return true;if(a == '[' && b == ']') return true;return false; } int main() {while(gets(str) != NULL){if(!strcmp(str, "end")) break;int len = strlen(str);for(int i = 0; i < len; i++){dp[i][i] = 0;if(judge(str[i], str[i+1]))dp[i][i+1] = 2;elsedp[i][i+1] = 0;}for(int k = 2; k < len; k++) //枚舉子串的長度{for(int i = 0; i + k < len; i++){int r = i + k;dp[i][r] = 0;if(judge(str[i], str[r]))dp[i][r] = dp[i+1][r-1] + 2;for(int j = i; j < r; j++)dp[i][r] = max(dp[i][r], dp[i][j] + dp[j+1][r]);}}printf("%d\n",dp[0][len-1]);}return 0; }

3.POJ 1141 Brackets Sequence http://poj.org/problem?id=1141

題意:給出一串由‘(‘,’)‘,’[',‘]’組成的字符串,求使原串里面的括號全部匹配后的長度最短的字符串。

狀態:dp[i][j] 表示使 i 到 j 全部匹配最少需要添加的括號個數。

轉移方程:dp[i][j] = min(dp[i][j], dp[i][k] + dp[i+1][k]);

#include<stdio.h> #include<string.h> #define INF 0x3ffffff const int N = 105; char str[N]; int dp[N][N], flag[N][N];bool judge(char a, char b) {if(a == '(' && b == ')') return true;if(a == '[' && b == ']') return true;return false; }void print(int i, int j) {if(i > j) return ;if(i == j){if(str[i] == '[' || str[i] == ']') printf("[]");else printf("()");}else if(flag[i][j] == -1){printf("%c",str[i]);print(i+1, j-1);printf("%c",str[j]);}else{print(i, flag[i][j]);print(flag[i][j] + 1, j);} }int main() {while(gets(str) != NULL){int len = strlen(str);memset(dp, 0, sizeof(dp));for(int i = 0; i < len; i++)dp[i][i] = 1;for(int i = 1; i < len; i++){for(int l = 0; l + i < len; l++){int r = l + i;dp[l][r] = INF;if(judge(str[l], str[r])){if(dp[l][r] > dp[l+1][r-1])dp[l][r] = dp[l+1][r-1], flag[l][r] = -1; //flag[l][r]=-1表示str[l]與str[j]匹配時最優}for(int k = l; k < r; k++)if(dp[l][r] > dp[l][k] + dp[k+1][r])dp[l][r] = dp[l][k] + dp[k+1][r], flag[l][r] = k; //flag[l][r]=k表示以k為分割點的兩端的匹配之和最優}}//printf("%d\n",dp[0][len-1]);print(0, len-1);printf("\n");}return 0; }

總結

以上是生活随笔為你收集整理的区间dp小结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。