回复:(野比)[全民编程]76道高难度C++练习题.含NOI竞...
											 /*---------------------------------------------------------------------------
File name:      C76-45.cpp
Author:         HJin (email: fish_sea_bird [at] yahoo [dot] com)
Created on:     7/3/2007 17:18:43
Environment:    Windows XP Professional SP2 English +
                Visual Studio 2005 v8.0.50727.762
Modification history:
===========================================================================
Problem statement:
---------------------------------------------------------------------------
经典 76 道编程题 之 45:
45. (数列的最小代价) 给定一个正整数序列,例如:4,1,2,3, 不改变数的位置把
它们相加, 并且由括号来标记每一次加法所得到的和。例如:((4+1)+(2+3))=
((5)+(5))=10. 除去原数4、1、2、3之外,其余都为中间结果,如:5,5,10, 将中
间结果相加,得到:5+5+10=20, 数 20 称为此数列的一个代价。对于另一种算法:
(4+((1+2)+3))=(4+((3+3))=(4+(6))=10, 得到数列的另一个代价为:3+6+10=19.
若给出 N 个数的数列,求出此数列的最小代价。
Analysis:
---------------------------------------------------------------------------
The minimum sequence price (SMP) problem:
For n numbers a_1 ... a_n, we need to do n-1 additions, thus there are
n-1 intermediate results. Our goal is to make the sum of these n-1
intermediate results as small as possible.
Let P_{i..j} be the sub-problem for a_i ... a_j, 1<=i <=j <=n, and m[i, j]
the corresponding minimum price. Then
m[i, j] = 0, if i=j;                                                    (1)
        = min_{i<=k<j} { m[i, k], m[k+1, j]} + (a_i + ... + a_j)
          if i<j.
Note that the formula (1) is very similar to the matrix chain order problem
introduced on CLRS [2]'s book.
m[1, n] gives the minimum price for a_1 .... a_n. To track back where we should
put the parentheses, we use another matrix to keep record of the k which minimizes
the equation in (1).
Sample output:
---------------------------------------------------------------------------
Optimal solution is:
(4+((1+2)+3))
Minimum sequence price is 19.
Press any key to continue . . .
Optimal solution is:
(((((1+2)+3)+(4+5))+(6+7))+((8+9)+10))
Minimum sequence price is 173.
Press any key to continue . . .
Optimal solution is:
(((1+-2)+(9+-3))+10)
Minimum sequence price is 25.
Press any key to continue . . .
Reference:
---------------------------------------------------------------------------
1. 野比, [全民编程]76道高难度C++练习题
https://bbs.bc-cn.net/viewthread.php?tid=147967
2. CLRS, introduction to algorithms, 2nd ed, MIT press.
*/
#include <iostream>
using namespace std;
#define INFPos (~(1<<31))
#define DIM(a) sizeof( (a) ) / sizeof ( (a)[0] )
/** Implement formula (1).
O(n^3) time + O(n^2) space.
*/
int smp(int*a, int n);
/**
Print the optimal solutions (the parentheses) recursively.
*/
void printOptSoln(int**s, int*a, int i, int j);
template <class T>
T** new2dInit(int row, int col)
{
    T** arr2d = new T*[row];
    int i;
    int j;
    for(i=0; i<row; ++i)
    {
        arr2d[i] = new T[col];
    }
    for(i=0; i<row; ++i)
    {
        for(j=0; j<col; ++j)
        {
            arr2d[i][j] = T();
        }
    }
    return arr2d;
}
template <class T>
void delete2d(T** arr2d, int row)
{
    for(int i=0; i<row; ++i)
    {
        delete [] arr2d[i];
    }
    delete [] arr2d;
}
int main()
{
    // test #1
    int a[] = {4, 1, 2, 3};
    smp(a, DIM(a));
    // test #2
    //int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    //smp(a, DIM(a));
    // test #3 --- numbers can be negative
    //int a[] = {1, -2, 9, -3, 10};
    //smp(a, DIM(a));
    return 0;
}
int smp(int*a, int n)
{
    int** m;
    int** s;
    int i;
    int j;
    int k;
    int l; // length of a subproblem  P_{i..j}
    int q;
    int sum; // a_i + ... + a_j
    m = new2dInit<int>(n, n);
    s = new2dInit<int>(n, n);
    for (l=2; l<=n; ++l)
    {
        for (i=0; i<=n-l; ++i)
        {
            j = i+l-1;
            // assign m[i,j] to be \+inf
            m[i][j] = INFPos;
            
            /**
            This sum has been repeatedly calculated.
            You could use another 2d buffer to store the
            results. The situation is that we have two choices here:
            choice #1: 3n^2 space + n^3 time (allocate a new 2d buffer for the sums)
            choice #2: 2n^2 space + 2n^3 time.
            As implemented, we are using choice #2.
            */
            sum = 0;
            for (k=i; k<=j; ++k)
            {
                sum += a[k];
            }
            for (k=i; k<j; ++k)
            {
                // implement (1)
                q = m[i][k] + m[k+1][j] + sum;
                if ( m[i][j] > q )
                {
                    m[i][j] = q;
                    s[i][j] = k;
                }
            }
        }
    }
    cout<<"Optimal solution is:\n";
    printOptSoln(s, a, 0, n-1);
    j = m[0][n-1]; // reuse j to keep m[0][n-1]
    cout<<"\nMinimum sequence price is "<<j<<"."<<endl;
    // free memory
    delete2d<int>(m, n);
    delete2d<int>(s, n);
    return j;
}
void printOptSoln(int** s, int*a, int i, int j)
{
    if(i==j)
    {
        cout<<a[i];
    }
    else
    {
        cout<<"(";
        printOptSoln(s, a, i, s[i][j]); // i..k
        cout<<"+";
        printOptSoln(s, a, s[i][j]+1, j); // k+1..j
        cout<<")";
    }
}