前言
最近在牛客网上找了点阿里巴巴笔试的编程题做,现在做个简单的总结。有的代码还在调,会慢慢发出来。有的问题可以直接暴力破解的就不放出来了,一般那种问题几层循环就解决了。不过笔试编程对时间和空间都有要求,有的题可能会过不了。如果题目本身比较有意义,我也会放到下面。
题目 1:
问题描述:小明在双十一晚会上抽奖赢得了一次天猫超市免单的机会,享受在一个包裹内最大体积V,最大重量M内免单。假设商品i,体积Vi,重量Mi,库存Si,价格Pi目前天猫超市的商品分为生鲜水产(1)、食品酒水(2)、美妆个护(3)和居家生活(4)四大类,且生鲜水产不与美妆个护同包裹,请你帮助小明在购物车里添置商品使得总价值最大 。
首先这个用例是错误的,我也是编完程才发现的。官方给的用例结果是33,很明显就是第二种商品拿3个。但事实,要想达到最大价值,需要取第三种商品5个,再拿一个第二种商品,此时volume = 28,wight = 30,value = 36符合要求。
解题思路:刚开始时,我一直在纠结两个物品不能同包裹这一条件,所以将问题想的太复杂了。后来发现,我完全可以创建 2 个vector,一个放水产和其他物品,另一个放美妆和其他物品。最后通过取两种情况的最大价值便可以得到答案。通过上面的思路,将问题转换成类似0-1背包问题。
代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
struct goods
{
int wight; //物品重量
int volume; //物品体积
int value; //物品价值
};
int goodssuma1 = 0, goodssuma2 = 0; //用来记录向量的长度
int Bagvolume,Bagwight,bestValue = 0; //代表包裹的容量和能承受的重量
int Cvalue,Cwight,Cvolume; //代表目前的价值,质量和容量
vector<goods> a1, a2; //a1放水产+其他商品,a2放美妆+其他商品
int Force(int i, const vector<goods> &x, int goodssum){
if(i > goodssum-1)
{
if(bestValue < Cvalue && Cwight <= Bagwight && Cvolume <= Bagvolume)
bestValue = Cvalue;
return bestValue;
}
Cwight = Cwight + x[i].wight; //拿这件商品
Cvalue = Cvalue + x[i].value;
Cvolume = Cvolume + x[i].volume;
if(Cwight <= Bagwight && Cvolume <= Bagvolume) //超过任一要求就不需要再往下递归了
Force(i+1, x, goodssum);
Cwight = Cwight - x[i].wight; //不拿这件商品
Cvalue = Cvalue - x[i].value;
Cvolume = Cvolume - x[i].volume;
if(Cwight <= Bagwight && Cvolume <= Bagvolume)
Force(i+1, x, goodssum);
return bestValue;
}
int main()
{
int goodsnum,goodsvolume, goodswight, goodsn, goodsvalue, number, maxsum;
goods asd;
printf("物品种类、最大体积及最大重量:");
scanf("%d,%d,%d", &goodsnum, &Bagvolume, &Bagwight);
while(goodsnum--)
{
//商品输入是:体积,重量,库存,价钱 和 商品编号
printf("输入数据:");
scanf("%d,%d,%d,%d,%d", &goodsvolume, &goodswight, &goodsn, &goodsvalue, &number);
asd.wight = goodswight;
asd.volume = goodsvolume;
asd.value = goodsvalue;
if(number == 1)
{
while(goodsn--)
a1.push_back(asd);
}
else if(number == 3)
{
while(goodsn--)
a2.push_back(asd);
}
else
{
while(goodsn--)
{
a1.push_back(asd);
a2.push_back(asd);
}
}
}
goodssuma1 = a1.size();
goodssuma2 = a2.size();
int sum1 = Force(0, a1, goodssuma1);
bestValue = 0;
Cvalue = Cwight = Cvolume = 0;
int sum2 = Force(0, a2, goodssuma2);
if(sum1 > sum2)
maxsum = sum1;
else
maxsum = sum2;
printf("装入最大总价值[%d]\n",maxsum);
return 0;
}
题目 2:
问题描述:
有一个整数n,你需要经过若干次操作,使 n 不小于 m。可以对n完成以下操作:
操作1:将n变更为 2*n ,花费为w2;
操作2:将n变更为 3*n ,花费为w3。
当满足n不小于m时,输出最小花费。
输入描述:
输入第一行一个整数 T,代表测试 T 组数据。接下来 T 行,每行有4个整数,n, m, w2, w3。其中 1 <= T <= 10000, 1 <= n,m <= 2^(31) - 1, 1 <= w2,w3 <= 1000。
输出:
对于每组数据,输出一个整数代表最小花费。
input:
1 6 2 3
4 32 3 4
2 1 1 2
1 2147483647 1 4
output:
5
9
0
31
解题思路:这两道题都是在求最优解,思路很相似,但是问题 2相对而言复杂一点。一方面是因为原题题干给的信息很难读懂,另一方面原因是原题输出的第二个示例答案给的是 8 ,正确答案应该是 9。这导致我开始没有理解题目的意思,编程半小时,调试一整天,最后还得不到正确答案。当时人都崩溃了。发现不对后又开始重新看题,捋清楚题干后总算是把题做出来了,第二道题就花了我 2 天时间(太难受了)。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int w2,w3,Ccount = 0;
int bestcount = 999;
long n,m;
int asd(int i)
{
if(i == 0 && n >= m)
return 0;
if(n < m)
{
n *= 2;
Ccount = Ccount + w2;
if(n >= m && bestcount > Ccount)
{
bestcount = Ccount;
return bestcount;
}
else
asd(i+1);
n /= 2;
Ccount = Ccount - w2;
n *= 3;
Ccount = Ccount + w3;
if(n >= m && bestcount > Ccount)
{
bestcount = Ccount;
return bestcount;
}
else
asd(i+1);
n /= 3;
Ccount = Ccount - w3;
}//if(n < m) end
return bestcount;
}
int main()
{
int times, value;
cin >> times;
while(times--)
{
cin >> n >> m >> w2 >> w3;
value = asd(0);
Ccount = 0;
bestcount = 999; //就是因为忘了重置,让我调试了半天
cout << value <<endl;
}
return 0;
}