MS2023正式批笔试


前言

在leetcode看到的
来源:ms笔试题


一、思路

  1. 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件物品。

  1. 转换到本题中
    车是物品,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);
  1. 优化空间
    通过01背包的优化方法可知:i-1可以由倒序遍历方式获得。
    因此优化的方程为:
dp[j][k]=max(dp[j][k],dp[j-h[i]][k]+1,dp[j][k-h[i]]+1);
  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;
} 

总结

  1. 时间: O(NXY)
    空间:O(X*Y)
    有一说一,这个测了自己样例,不知道有没有没考虑到的地方。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值