题目:
给定长为n的字符串,以及一串切割的位置,由于每一次切割字符串都需要拷贝字符串,因此每次切割的时候的代价均为O(n)。其中n代表字符串的长度。例如给定一个长为10的字符串以及切割位置为2、4、7.则如果我们按顺序切割时,总的代价为10+8+6=24,即第一次切割2位置处,剩余长度为8的子串;第二次切割4位置处,剩余长度为6的子串;最后一次在位置7处切割。但是最优的切割顺序是:4、2、7,这样总的代价为10+4+6=20.
现在要求求给定一个长度和一系列切割点,求最小的切割代价。
分析:
这是一道典型的动态规划的题目,用动态规划来求解非常的直观明了。设切割点的个数为n个,其中第一个切割点为0,最后一个切割点为字符串的长度m,用数组C来表示。那我们用一个nxn的矩阵P来存储中间状态。其中P[i][j]表示切割从底i个切割点到第j个切割点这段字符串的切割的代价,切割这个子串时,切割点为C[i+1]~C[j-1]。那么我们便能够得出递归表达式为:
P[i][j] = C[j]-C[i] + min{P[i][k] + P[k][j] | i < k < j}
有了这个递归表达式,那代码的编写便不难了,参考代码如下:
#include <iostream>
#include <vector>
using namespace std;
int minCutCost(int *cuttingPoint, int n)
{
vector<vector<int> > p(n);
int i = 0, j = 0, k = 0;
for(i = 0; i < n-1; i++) p[i].resize(n);
for(j = 2; j < n; j++)
{
for(i = j-2; i >= 0; i--)
{
int minCost = INT_MAX;
int len = cuttingPoint[j] - cuttingPoint[i];
for(k = i+1; k < j; k++)
{
minCost = (len + p[i][k] + p[k][j] < minCost)?(len + p[i][k] + p[k][j]):minCost;
}
p[i][j] = minCost;
}
}
return p[0][n-1];
}
int main()
{
int len, n;
int cuttingPoint[100] = {0};
while(cin >> len >> n)
{
cuttingPoint[0] = 0;
cuttingPoint[n+1] = len;
for(int i = 1; i <= n; i++) cin >> cuttingPoint[i];
cout << minCutCost(cuttingPoint, n+2) << endl;
}
return 0;
}