题目大意:给你一串数字让你判断经过若干次合并,使得这个数字串变成回文串的最小成本是多少。第一行是数字串,第二行是合并连续i个数字的成本是多少。
解题思路:区间dp,可以进行记忆化搜索,如果左边比右边和大那么右边一定是小了,右边比左边大那么左边一定小了。因为保证有解。具体不太好说,直接看代码吧。
5 6 2 8 7 1 0 5 2 10 20 0
10HintIn the sample, there is two ways to achieve Xiaoji‘s goal. [6 2 8 7 1] -> [8 8 7 1] -> [8 8 8] will cost 5 + 5 = 10. [6 2 8 7 1] -> [24] will cost 20.
#include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #include <iomanip> #include <stdio.h> #include <string> #include <queue> #include <cmath> #include <stack> #include <map> #include <set> #define eps 1e-10 ///#define M 1000100 ///#define LL __int64 #define LL long long ///#define INF 0x7ffffff #define INF 0x3f3f3f3f #define PI 3.1415926535898 #define zero(x) ((fabs(x)<eps)?0:x) using namespace std; const int maxn = 5010; int dp[maxn][maxn]; LL sum[maxn]; int num[maxn]; int dfs(int l, int r) { if(l > r) return 0; if(dp[l][r] != -1) return dp[l][r]; dp[l][r] = num[r-l+1]; int ll = l, rr = r; while(ll < rr) { if((sum[ll]-sum[l-1]) > (sum[r]-sum[rr-1])) rr--; else if((sum[ll]-sum[l-1]) < (sum[r]-sum[rr-1])) ll++; else if((sum[ll]-sum[l-1]) == (sum[r]-sum[rr-1])) { dp[l][r] = min(dp[l][r], num[ll-l+1]+dfs(ll+1, rr-1)+num[r-rr+1]); rr--; } } return dp[l][r]; } int main() { int n; while(~scanf("%d",&n) && n) { sum[0] = 0; for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) dp[i][j] = -1; LL x; for(int i = 1; i <= n; i++) { scanf("%I64d",&x); sum[i] = sum[i-1]+x; } for(int i = 1; i <= n; i++) scanf("%d",&num[i]); cout<<dfs(1, n)<<endl; } return 0; }
HDU 4960 Another OCD Patient(区间dp记忆化搜索)
原文:http://blog.csdn.net/xu12110501127/article/details/38853273