前言
最近在牛客網上找了點阿里巴巴筆試的編程題做,現在做個簡單的總結。有的代碼還在調,會慢慢發出來。有的問題可以直接暴力破解的就不放出來了,一般那種問題幾層循環就解決了。不過筆試編程對時間和空間都有要求,有的題可能會過不了。如果題目本身比較有意義,我也會放到下面。
題目 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);
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;
}