题目描述:
给一个 n 英寸长的杆子和一个包含所有小于 n 的尺寸的价格. 确定通过切割杆并销售碎片可获得的最大值.例如,如果棒的长度为8,并且不同长度部件的值如下,则最大可获得值为 22(通过切割两段长度 2 和 6 )。
样例:
长度 | 1 2 3 4 5 6 7 8
价格 | 1 5 8 9 10 17 17 20
给出 price = [1, 5, 8, 9, 10, 17, 17, 20], n = 8 返回 22//切成长度为 2 和 6 的两段
长度 | 1 2 3 4 5 6 7 8
价格 | 3 5 8 9 10 17 17 20
给出 price = [3, 5, 8, 9, 10, 17, 17, 20], n = 8 返回 24//切成长度为 1 的 8 段
标签:
背包问题、动态规划
思路讲解:
我第一眼看到的想法就是利用动态规划中的01背包问题来做,不过,这里不仅仅是简单的01背包问题,因为这里允许每一种可以拿多个,这就导致其跟原来的不一样了(原来的是拿与不拿的问题),这样的问题我们成为完全背包问题,我选择了其中的两种做法进行操作:
第一种是将这种问题转换为简单的01背包问题,我们可以将每一种长度物品变为n个一样长度的物品(这里的n是背包能装的最多个数)这样就转换为01背包问题了。
举个例子:
原本的数据:
棒的长度为4
长度 | 1 2 3
价格 | 3 5 8
转换后为:
长度 | 1 1 1 1 2 2 3
价格 | 3 3 3 3 5 5 8
这样我们就可以继续使用01背包问题的状态转移方程map[i][j]=max(map[i-1][j],(map[i][j-weight[i-1]]+prices[i-1]))对这个问题进行求解了。
详细代码:
class Solution {
public:
/*
* @param : the prices
* @param : the length of rod
* @return: the max value
*/
int cutting(vector<int>& prices, int n) {
// Write your code here
int N=prices.size();
int V=n;
vector<int>weight;
for(int i=0;i<N;i++)
{
weight.push_back(i+1);
}
for(int i=0;i<N;i++)
{
int count=n/weight[i];
int tmp1=weight[i];
int tmp2=prices[i];
for(int j=1;j<count;j++)//将无数个转换为具体的个数
{
weight.push_back(tmp1);
prices.push_back(tmp2);
}
}
N=weight.size();
V=n;
sort(weight.begin(),weight.end());
sort(prices.begin(),prices.end());
int **map=new int*[N+1];
for(int i=0;i<=N;i++)
{
map[i]=new int[V+1];
}
for(int i=0;i<=N;i++)
{
for(int j=0;j<=V;j++)
{
map[i][j]=0;
}
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=V;j++)
{
map[i][j]=max(map[i-1][j],j-weight[i-1]>=0?(map[i][j-weight[i-1]]+prices[i-1]):0);//状态转移方程
}
}
//printvector(weight);
// printvector(prices);
//print2Darray(map,N,V);
return map[N][V];
}
void print2Darray(int **p,int a,int b)
{
for(int i=0;i<=a;i++)
{
for(int j=0;j<=b;j++)
{
cout<<p[i][j]<<" ";
}
cout<<endl;
}
}
void printvector(vector<int>res)
{
for(int i=0;i<res.size();i++)
{
cout<<res[i]<<" ";
}
cout<<endl;
}
};
第二种方法:由于在原来的01背包问题中,我们只需要选择选或者不选,但是这里我们不仅要决定选或者不选,还要决定选取的个数即取0个、取1个、取2个、取3个直到背包放不下。所以,我们可以对原来的状态转移方程进行改造原来的是map[i][j]=max(map[i-1][j],(map[i][j-weight[i-1]]+prices[i-1])),我们可以发现这里-weight[i]只减去一个,所以我们可以在这里加上一个变量K,即变成map[i][j]=max(map[i][j],map[i-1][j-k*i]+k*prices[i-1])这样,我们只需要在每一次循环K的个数即可,(0<=K<=n/weight[i])即可。
详细代码:
class Solution {
public:
/*
* @param : the prices
* @param : the length of rod
* @return: the max value
*/
int cutting(vector<int>& prices, int n) {
// Write your code here
int N=prices.size();
int V=n;
int **map=new int*[N+1];
for(int i=0;i<=N;i++)
{
map[i]=new int [V+1];
}
for(int i=0;i<=N;i++)
{
for(int j=0;j<=V;j++)
{
map[i][j]=0;
}
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=V;j++)
{
int ncount=j/i;
for(int k=0;k<=ncount;k++)
{
map[i][j]=max(map[i][j],map[i-1][j-k*i]+k*prices[i-1]);//重点的转移方程
}
}
}
//print2Darray(map,N,V);
return map[N][V];
}
void print2Darray(int **p,int a,int b)
{
for(int i=0;i<=a;i++)
{
for(int j=0;j<=b;j++)
{
cout<<p[i][j]<<" ";
}
cout<<endl;
}
}
};