前言
在leetcode看到的
来源:ms笔试题
一、思路
- 01背包的动态转移方程(二维):
dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
其中dp[i-1][j]
表示不放第i件物品,dp[i-1][j-weight[i]]+value[i]
表示放第i件物品。
- 转换到本题中
车是物品,x,y为背包重量,value就是1
对于第i辆车,每个车有三种选择,不放,放x,放y。
可得转移方程:
dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-h[i]][k]+1,dp[i-1][j][k-h[i]]+1);
- 优化空间:
通过01背包的优化方法可知:i-1可以由倒序遍历方式获得。
因此优化的方程为:
dp[j][k]=max(dp[j][k],dp[j-h[i]][k]+1,dp[j][k-h[i]]+1);
- 遍历顺序
都是倒序
二、代码
1.二维空间
代码如下(示例):
#include<bits/stdc++.h>
using namespace std;
int dp[1001][1001];
int carnum(vector<int>h,int x,int y)
{
//sort(h.begin(),h.end());
for(int i=h.size()-1;i>=0;i--)
//for(int i=0;i<h.size();i++)
{
for(int j=x;j>=0;j--)
{
//dp[j][0]=max(dp[j][0],dp[j-h[i]][0]+1);
for(int k=y;k>=0;k--)
{
//dp[j][k]=max(dp[j][k],dp[j][k-h[i]]+1);
if(j>=h[i]&&k>=h[i])
dp[j][k]=max(dp[j][k],max(dp[j-h[i]][k]+1,dp[j][k-h[i]]+1));
else if(j>=h[i])
dp[j][k]=max(dp[j][k],dp[j-h[i]][k]+1);
else if(k>=h[i])
dp[j][k]=max(dp[j][k],dp[j][k-h[i]]+1);
、、cout<<i<<" "<<j<<" "<<k<<":"<<dp[j][k]<<endl;
}
}
}
return dp[x][y];
}
int main()
{
int ans = 0,x=0,y=0;
vector<int> h = {1,1,3};//测试用的,随便改就是
x = 1;
y = 1;
cout<<carnum(h,x,y)<<endl;
return 0;
}
2.前缀和优化
没想出这种,看的评论区大佬。
1.首先排序 H 数组, 优先选造的时间少的车进行生产
2.假设我们要生产前 i 辆车, 那么, 我们分配给产线 X 的时间越多(但是不能超过X), 产线 Y 的压力就越小, 方案更优(反证: 假设有最优方案, 但是该方案分配给 X 的时间不是最多的, 那么我们完全可以转换到分配给 X 更多时间的方案)
3.我们可以通过动态规划来求前 i 辆车,最多分配给 X 多少时间:令 dp[i][j] = 1 表示前 i 辆车, 可以分配给产线 X j 小时的时间,dp[i][j] = 0 表示前 i 辆车,不能分配给产线 X j 小时的时间.
4.依次检查每一个 i,如果前 i 辆车的时间之和 - 产线 X 的最多时间 <= 产线 Y 的时间,那么就能生产前 i 辆车。
时间复杂度为 O(N * min(X,Y))
作者:newhar
链接:思路
来源:力扣(LeetCode)
代码如下(示例):
#include<bits/stdc++.h>
using namespace std;
int dp[1001][1001];
int carnum(vector<int>h,int x,int y)
{
if(x>y)swap(x,y);
sort(h.begin(),h.end());
//greedy, always try to choose shorter h
vector<int>presum(h.size(),0);
presum[0]=h[0];
for(int i=1;i<h.size();i++)
{
presum[i]=presum[i-1]+h[i];
}
//DP[i][j] means: Can small factory cover exactly j hours considering car[0,i]
dp[0][0]=1;
if(x>=h[0])dp[0][h[0]]=1;
for(int i=1;i<h.size();i++)
{
for(int j=0;j<=x;j++)
{
if(dp[i-1][j])dp[i][j]=1;
if(j-h[i]>=0 && dp[i-1][j-h[i]]) dp[i][j] = 1;
}
}
//final result
for(int i=h.size()-1; i>=0; i--)
{
//what is the max of small factory cover
int max = 0;
for(int j=x; j>=0; j--)
{
if(dp[i][j])
{
max = j;
break;
}
}
if(presum[i]-max <= y) return i+1;
}
return 0;
}
int main()
{
int ans = 0,x=0,y=0;
vector<int> h = {6,5,2,1,8};//测试用的,随便改就是
x = 17;
y = 5;
cout<<carnum(h,x,y)<<endl;
return 0;
}
总结
- 时间: O(NXY)
空间:O(X*Y)
有一说一,这个测了自己样例,不知道有没有没考虑到的地方。。。