设有一个长度为L的钢条,在钢条上标有n个位置点(p1,p2,…,pn)。现在需要按钢条上标注的位置将钢条切割为n+1段。假定每次切割所需要的代价与所切割的钢条长度成正比。请编写一个算法,能够确定一个切割方法,使切割的总代价最小。
输入:
7 4
5 4 3 1
结果:
16
思路
先定义一维数组p[ n+1 ],其中p[i]是第i个切割点的位置(注意p应为有序的)。特别地,p[ 0 ]=0,p[ n+1 ]=L。
用a[ i ][ j ]记录从第i个切割点到第j个切割点的最小代价。其最优子结构的递归关系为:
j - i =1时,a[ i ][ j ] = 0;
j - i =2时,a[ i ][ j ] = p[ j ] - p[ i ];
3 ≤ j - i 时,a[ i ][ j ] = min{ p[ j ] - p[ i ] +a[ i ][ k ] +a[ k ][ j ] },i+1 ≤ k ≤ j-1。
最后a[ 0 ][ n+1 ]即为所求。时间复杂度为O(n^2)。
代码
#include<iostream>
using namespace std;
void bubbleSort(int *p, int n)
{
for(int i=1;i<n+1;i++){
for(int j=1;j<n-i+1;j++){
if(p[j+1]<p[j]){
int temp = p[j];
p[j] = p[j+1];
p[j+1] = temp;
}
}
}
}
int min(int a, int b)
{
return a<b?a:b;;
}
int Solution(int begin, int end, int *p, int **a)
{
if(end-begin==1)
return 0;
else if(end-begin==2)
return p[end]-p[begin];
else{
int least=a[begin][begin+1]+a[begin+1][end]+p[end]-p[begin];
for(int i=2;i<end-begin;i++){
least = min(least, a[begin][begin+i]+a[begin+i][end]+p[end]-p[begin]);
}
return least;
}
}
int main()
{
int L, n;
cin>>L>>n;
int *p;
p = new int[n+2];
p[0] = 0;
for(int i=1;i<n+1;i++){
cin>>p[i];
}
bubbleSort(p, n);
p[n+1] = L;
int **a = new int*[n+2];//创建二维数组记录最小代价值
for(int i=0;i<n+2;i++){
a[i] = new int[n+2];
}
for(int i=1;i<n+2;i++){
for(int j=0;j<n+2-i;j++){
a[j][i+j] = Solution(j,i+j,p,a);
}
}
cout<<Solution(0,n+1,p,a);
return 0;
}