【HDU4960】区间dp 分治法~

Another OCD Patient

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 663    Accepted Submission(s): 247


Problem Description
Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morning, his children played with plasticene. They broke the plasticene into N pieces, and put them in a line. Each piece has a volume Vi. Since Xiaoji is an OCD patient, he can't stand with the disorder of the volume of the N pieces of plasticene. Now he wants to merge some successive pieces so that the volume in line is symmetrical! For example, (10, 20, 20, 10), (4,1,4) and (2) are symmetrical but (3,1,2), (3, 1, 1) and (1, 2, 1, 2) are not.

However, because Xiaoji's OCD is more and more serious, now he has a strange opinion that merging i successive pieces into one will cost ai. And he wants to achieve his goal with minimum cost. Can you help him?

By the way, if one piece is merged by Xiaoji, he would not use it to merge again. Don't ask why. You should know Xiaoji has an OCD.
 

Input
The input contains multiple test cases.

The first line of each case is an integer N (0 < N <= 5000), indicating the number of pieces in a line. The second line contains N integers Vi, volume of each piece (0 < Vi <=10^9). The third line contains N integers ai  (0 < ai <=10000), and a1 is always 0. 

The input is terminated by N = 0.
 

Output
Output one line containing the minimum cost of all operations Xiaoji needs.
 

Sample Input
 
   
5 6 2 8 7 1 0 5 2 10 20 0
 

Sample Output
 
   
10
Hint
In 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.
 

Author
SYSU
 

Source
2014 Multi-University Training Contest 9

参考:http://blog.csdn.net/houserabbit/article/details/38686847

题意:给你一串数字  相邻x个数字合并成一个数字(相加)有一定代价  问  最少花费多少使得串变成回文串

思路:

读完题感觉像dp  数据范围也像  就开始想怎么表示状态  最简单的应该想到dp[i][j]表示i到j区间变成回文串的最小花费  状态想好了想做法  考虑将串分成AAAABBBBBBBCCC三段  即所有A合成一个数字  C也是  而且A和C相等  那么B串就变成了子问题  但是A和C是不是都要枚举呢?  这个串所有元素都是正的  那么也就是对于一种A只能对应一种C  所以这个枚举复杂度是O(n)的  而且每次做子问题都会至少去掉首尾2个元素  那么复杂度也就是n^2级别

代码:


#define DeBUG
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std ;
#define zero {0}
#define INF 0x3f3f3f3f
#define EPS 1e-6
#define TRUE true
#define FALSE false
typedef long long LL;
const double PI = acos(-1.0);
//#pragma comment(linker, "/STACK:102400000,102400000")
inline int sgn(double x)
{
    return fabs(x) < EPS ? 0 : (x < 0 ? -1 : 1);
}
#define N 5010
int n;
int dp[N][N];
int cost[N];
long long sum[N];
int dfs(int l, int r)
{
    if (l >= r)return 0;
    if (dp[l][r] != INF)return dp[l][r];
    dp[l][r] = cost[r - l + 1];
    long long suml, sumr;
    for (int i = l, j = r; i < j;)
    {
        suml = sum[i] - sum[l - 1];
        sumr = sum[r] - sum[j - 1];
        if (suml == sumr)
        {
            dp[l][r] = min(dp[l][r], dfs(i + 1, j - 1) + cost[i - l + 1] + cost[r - j + 1]);
            i++;
            j--;
        }
        else if (suml > sumr)j--;
        else
            i++;
    }
}
int main()
{
#ifdef DeBUGs
    freopen("C:\\Users\\Sky\\Desktop\\1.in", "r", stdin);
#endif
    while (scanf("%d", &n), n)
    {
        memset(sum, 0, sizeof(sum));
        for (int i = 1; i <= n; i++)
        {
            scanf("%I64d", &sum[i]);
            sum[i] = sum[i - 1] + sum[i];
        }
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &cost[i]);
        }
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                dp[i][j] = INF;
            }
        }
        dfs(1, n);
        printf("%d\n", dp[1][n]);
    }

    return 0;
}


你可能感兴趣的:(ACM-DP)