阿里2018暑期实习招聘在线编程题:订单分配

本文讲述了作者在阿里2018暑期实习招聘中遇到的一道在线编程题,涉及订单商品与预包装组合的最优匹配问题。题目要求通过编程找出使剩余商品种类最少且组合种类也最少的匹配方案。作者分享了使用C++解决该问题的思路和代码,并通过实例验证了程序的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阿里的在线编程题中有这么一道题:

一个淘宝的订单中包含n(10>=n>=1)种商品A1,A2,...,An,每种商品数量分别为a1,a2,...,an个,记做{a1,a2,...,an}(ak>0)。订单在仓库生产过程中,仓库为了提升作业效率,会提前对热门组合商品进行预包装。假设这n个商品有m(9>=m>=1)个商品组合,每个组合bomk包含A1,A2,...,An的数量分别为{b1,b2,...,bn}(bk>=0,至少存在一个bk>0)

 

举例如下:

订单包含A,B,C商品,数量为{2,3,1},商品组合bom1{2,1,1},bom2{1,1,0},bom3{0,1,1}

对以上订单匹配给定商品组合,得到的可能匹配结果为:res1.匹配到组合1一套,剩余B商品;res2.匹配到组合2两套,组合3一套,不剩商品;

现要求订单的最优匹配,最优匹配的原则为:1.匹配组合后,剩余商品种类数越少越好;2.在剩余商品种类数相同的情况下,匹配到的组合种类数越少越好;

例如上面例子,我们认为res2优于res1。

 

现需要编写程序,输入格式为:

n,m

a1,a2,...,an

bom1,b11,b12,...,b1n

bom2,b21,b22,...,b2n

....

bomm,bm1,bm2,...,bmn

 

输入数据的格式说明(数据间使用英文逗号分隔):


第一行数据:n个商品,m个预包方案

第二行数据:商品1个数,商品2个数,。。。,商品n个数

第三行数据:bom1,商品1个数,商品2个数,。。。,商品n个数

。。。。

第n行数据:bomn,商品1个数,商品2个数,。。。,商品n个数

 

针对输入数据找出最优匹配,输出最优匹配的组合及套数。


当时非常遗憾没做出来。最近这段时间空下来了,仔细思考一下,其实并不难。这就是一道典型的可以用搜索算法解决的问题。虽然阿里的开发语言主要是Java,但本人平时还是习惯使用C++,所以这道题就用C++来做了。

下面是我的C++代码。为了方便起见,就不按照在线编程的要求进行多次重复输入验证了,只测试一个用例。

#include <iostream>
#include <vector>

using namespace std;

bool canSearch(const vector<int> &bom, const vector<int> &left,int n) {
	//判断能否在剩余商品数量left中再挑选出bom组合
	for (int i = 0; i < n; i++) {
		if (left[i] - bom[i] < 0) return false;
	}
	return true;
}

bool allZero(const vector<int> &vec,int m) {
	//判断一个元素数量为m 的vector vec的元素是否全为0
	for (int i = 0; i < m; i++) {
		if (vec[i] != 0) return false;
	}
	return true;
}

bool isBetter(const vector<int> &left1, const vector<int> &left2,int n,const vector<int> &result1, const vector<int> &result2,int m) {
	//在result1和result2两种挑选方法下,剩余商品数量分别为left1和left2
      //比较这两种挑选方法哪个更好。如果result1好于retult2,返回true。否则返回false。
	int leftsize1=0, leftsize2=0;//剩余的商品种类
	for (int i = 0; i < n; i++) {
		if (left1[i] > 0) leftsize1++;
		if (left2[i] > 0) leftsize2++;
	}
	if (leftsize1 < leftsize2) return true;
	if (leftsize1 > leftsize2) return false;
	//剩余商品种类相等的情况下,匹配到的组合种类数越少越好
	int pipeisize1 = 0, pipeisize2 = 0;//匹配到的组合种类数
	for (int i = 0; i < m; i++) {
		if (result1[i] > 0) pipeisize1++;
		if (result2[i] > 0) pipeisize2++;
	}
	if (pipeisize1 <= pipeisize2) return true;
	else return false;
}

void search(const vector<int> &maters, const vector<vector<int>> &boms, vector<int> left, vector<int> tmpresult, vector<int> &result, int n, int m)
{
	bool flag = false;//能否再添加商品组合
	vector<int> tmpleft, tmp_tmpresult;
	for (int i = 0; i < m; i++) {
		if (canSearch(boms[i], left,n)) {
			if (!flag) flag = true;
			tmpleft = left;
			tmp_tmpresult = tmpresult;
			for (int j = 0; j < n; j++) {
				tmpleft[j] = left[j] - boms[i][j];
			}
			tmp_tmpresult[i] += 1;
			search(maters, boms, tmpleft, tmp_tmpresult, result, n, m);//还能够继续选出商品组合,递归搜索
		}
	}
	if (!flag) {
		//已经没办法再选择一个商品组合,搜索结束,此时得到的一个结果为tmpresult
		//将tmpresult与result比较,选一个更优的组合,保存在result中
		if (allZero(result, m)) result = tmpresult;//一开始result全0,说明result没被更新过,直接让result=tmpresult即可
		else {
			//计算在result的挑选方法下,剩余的商品currentbestleft
			vector<int> currentbestleft = maters;
			for (int i = 0; i < m; i++) {
				int number = result[i];
				for (int j = 0; j < n; j++) {
					currentbestleft[j] -= number*boms[i][j];
				}
			}
			//currentbestleft与left比较
			if (isBetter(left,currentbestleft, n, tmpresult, result,  m)) {
				//现在的结果更好,用现在的结果tmpresult替换之前的结果result
				result = tmpresult;
			}
		}
	}
}

int main()
{
	int n, m;
	cin >> n >> m;
	vector<int> maters(n);
	vector<vector<int>> boms(m);
	cout << "请输入" << n << "种商品的数量:" << endl;
	for (int i = 0; i < n; i++) {
		cin >> maters[i];
	}
	int tmp;
	cout << "请输入" << m << "种商品组合:" << endl;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> tmp;
			boms[i].push_back(tmp);
		}
	}
	vector<int> left = maters;
	vector<int> result(m), tmpresult(m);
	for (int i = 0; i < m; i++) {
		result[i] = 0; tmpresult[i] = 0;
	}
	search(maters, boms, left, tmpresult, result, n, m);
	cout << "最优的匹配结果为:" << endl;
	for (int i = 0; i < m; i++) {
		cout << result[i] << ' ';
	}
	cout << endl;
	system("pause");
	return 0;
}

就用题目中举出来的例子来验证一下程序的正确性吧:

再想一个例子:

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值