切割成本
描述
将一条长度为x的线段切成若干段,切割点已给出,每次切割的成本为切割后产生的两段线段长度之和,求最小的切割成本。
示例
输入:20,[2,5,10,18]
返回值:45
说明:线段长为20,切割点为[2,5,10,18]。
第一种方案:
1.先切开第一个点,成本为2+18=20
2.切开第二个点,成本为3+15=18
3.切开第三个点,成本为5+10=15
4.切开第四个点,成本为8+2=10
总成本为:20 + 18 + 15 + 10 = 63;
第二种方案:
1.先切开第一个点,成本为5+15=20
2.切开第二个点,成本为2+3=5
3.切开第三个点,成本为5+10=15
4.切开第四个点,成本为8+2=10
总成本为:20 + 5 + 15 + 10 = 50;
第一种方案:
1.先切开第一个点,成本为2+18=20
2.切开第二个点,成本为3+15=18
3.切开第三个点,成本为5+10=15
4.切开第四个点,成本为8+2=10
总成本为:20 + 18 + 15 + 10 = 63;
第二种方案:
1.先切开第一个点,成本为5+15=20
2.切开第二个点,成本为2+3=5
3.切开第三个点,成本为5+10=15
4.切开第四个点,成本为8+2=10
总成本为:20 + 5 + 15 + 10 = 50;
方法一
思路分析
本题采用动态规划即自下而上的办法,给定一长度为n的线段,由于不确定切割点的位置,因此找到所有的整数端点作为切割点,设置二维数组$array[i][j]$用于存储两个切割点之间的切割成本,为了找到每一线段的切割,设置线段的开始位置与结束位置作为切割点。采用自下而上的办法,即先算一个切割点到其他切割点的切割成本。设置$array[i][k]+array[k+1][j]+f[i]-f[j]$表示某一区间内切割点为k的最小切割成本。其状态转移方程如下:
图解
核心代码
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param monsterLength int整型 线段长度
* @param monsterPoint int整型vector 切割点位置
* @return int整型
*/
int attackMonster(int monsterLength, vector<int>& monsterPoint) {
// write code here
int n = monsterPoint.size();
vector<int> f;
vector<vector<int> > array(n+2);
for(int i=0;i<n+2;i++)
{
array[i].resize(n+2);
}
for(int i=0;i<n;i++)
{
f.push_back(monsterPoint[i]);
}
f.push_back(0);
f.push_back(monsterLength);//首尾节点加入切割数组中
sort(f.begin(),f.end());//对切割数组进行排序
int res=operation(n,array,f);
return res;
}
int operation(int n,vector<vector<int> > &array,vector<int>& f)
{
for(int i=0;i<n+1;i++)
{
array[i][i+1]=0;//单独的一段不可切割
}
for(int i=2;i<n+2;i++)//子区间长度
{
for(int j=1;j<n-i+3;j++)//子区间开始位置
{
array[j][j+i-1]=INT_MAX;
for(int m=j;m<j+i-1;m++)//找到切割点
{
array[j][j+i-1]=min(array[j][j + i - 1], array[j][m] + array[m + 1][j + i -1] + f[j + i -1] - f[j - 1]);
//切割点左边切割成本+切割点右边切割成本+区间右侧值-区间左侧值
}
}
}
return array[1][n+1];//第一个切割点到最后一个切割点的最小成本
}
}; 复杂度分析 - 时间复杂度:三层嵌套循环,最大时间复杂度为$O(n^3)$
- 空间复杂度:借助于一个大小为$n+2$的辅助数组用于存储切割点,借助一个大小为$(n+2)^2$的辅助数组用于存储区间切割成本,因此空间复杂度为$O(n^2)$
方法二
思路分析
二分法,建议再找一种办法。
核心代码
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param monsterLength int整型 线段长度
* @param monsterPoint int整型vector 切割点位置
* @return int整型
*/
vector<int >res;
vector<int> f;
int attackMonster(int monsterLength, vector<int>& monsterPoint) {
// write code here
int n = monsterPoint.size();
for(int i=0;i<n;i++)
{
f.push_back(monsterPoint[i]);
}
f.push_back(0);
f.push_back(monsterLength);//首尾节点加入切割数组中
sort(f.begin(),f.end());//对切割数组进行排序
int left=0;
int right=n+1;//最后一个位置切割点
int mid;
if((left+right)%2==0)
mid=(left+right)/2;
else
mid=(left+right)/2+1;
res.push_back(monsterLength);
operation(0,mid-1,f[mid]);
operation(mid+1,n+1,monsterLength-f[mid]);
int m=res.size();
int ans=0;
for(int i=0;i<m;i++)
ans+=res[i];
return ans;
}
void operation(int left,int right,int length)
{
if((right-left)==1)
{
res.push_back(length);
return;
}
int mid;
if((left+right)%2!=0)
mid=(left+right)/2;
else
mid=(left+right)/2+1;
res.push_back(f[mid]+length-f[mid]);
operation(left,mid-1,f[mid]);
operation(mid+1,right,length-f[mid]);
}
}; 
京公网安备 11010502036488号