1. 程式人生 > 其它 >牛客網 華為 機試 HJ16 購物單

牛客網 華為 機試 HJ16 購物單

題目地址:https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4?tpId=37&tqId=21239&rp=1&ru=/ta/huawei&qru=/ta/huawei&difficulty=&judgeStatus=&tags=/question-ranking

/*
一看就是揹包問題,但是題目中對01揹包進行了條件的新增,但主要思路不變,依舊嘗試還原為簡單的01揹包問題。
具體實現思路是將附屬物品看作是主物品的一種屬性,將特殊的物品之間的關係還原為01揹包是解題關鍵。
由題意可知,一個主物品可以不存在附屬物品,或者有一個附屬物平,或者有兩個,因此可將揹包的情況擴充。
主要分為4種情況:
  1、不放入;
  2、放入但不放入主物品的附屬;
  3、放入且放入其中一個附屬物品(放入哪個就要再分為兩種情況考慮);
  4、放入且放入兩個附屬物品;
  這樣就不需要考慮附屬物品與主物品之間的關係,還原成熟悉的01揹包問題了。
*/ #include<bits/stdc++.h> using namespace std; //存放物品資訊的結構體 struct Thing{ int price = 0; int importance = 0; int kind = 0; //此物品是主物品還是副物品 Thing* firstAppendix = NULL; //此主物品對應的第一個附屬物品 Thing* secondAppendix = NULL; //此主物品對應的第二個附屬物品 }; int main(void){ int money = 0; int count = 0
; cin >> money; cin >> count; Thing things[count];//先把所有物品的資訊存放在things中 for(int i = 0;i < count;i++){ cin >> things[i].price >> things[i].importance >> things[i].kind; things[i].price /= 10;//由於所有價格都是10的倍數因此可以先縮放10倍減少運算開銷 } vector<vector<int>> bag;//
申請揹包空間 vector<int> wide(money / 10 + 1);//揹包的“寬度”是依據輸入的money所決定的,此基礎上再新增一列代表了揹包列初始狀態 bag.push_back(wide);//揹包行初始狀態 //遍歷找到所有附屬物品並將其地址寫入其主物品的相關屬性中(firstAppendix和secondAppendix) for(int i = 0;i < count;i++){ if(things[i].kind != 0){ if(things[things[i].kind - 1].firstAppendix == NULL){ //注意兩個附屬物品肯定不重複,要進行條件判斷 things[things[i].kind - 1].firstAppendix = &things[i]; }else{ things[things[i].kind - 1].secondAppendix = &things[i]; } } } vector<Thing> thingsVec;//thingsVec用來存放所有主物品 Thing nullThing; thingsVec.push_back(nullThing);//初始化thingsVec時為了後續操作方便,將角標後移,以便於對應揹包的角標 //遍歷things將主物品全部放入thingsVec for(int i = 0;i < count;i++){ if(things[i].kind == 0){ bag.push_back(wide); thingsVec.push_back(things[i]); } } //開始揹包運算,注意是遍歷thingsVec中的所有主物品,已經排除了附屬物品 for(int i = 1;i < bag.size();i++){ for(int j = 1;j < wide.size();j++){ //不放的情況 int notPutIn = bag[i - 1][j]; //放入但不放入其附屬物品 int putInWithoutAppendix = (j - thingsVec[i].price >= 0) ? bag[i - 1][j - thingsVec[i].price] + thingsVec[i].price * thingsVec[i].importance :0; //放入且放入第一個附屬物品(對應附屬物品存在並且放得下) int putInWithFirstAppendix = (thingsVec[i].firstAppendix != NULL) ? (j - thingsVec[i].price - thingsVec[i].firstAppendix->price >= 0) ? bag[i - 1][j - thingsVec[i].price - thingsVec[i].firstAppendix->price] + thingsVec[i].price * thingsVec[i].importance + thingsVec[i].firstAppendix->price * thingsVec[i].firstAppendix->importance :0 :0; //放入且放入第二個附屬物品(對應附屬物品存在並且放得下) int putInWithSecondAppendix = (thingsVec[i].secondAppendix != NULL) ? (j - thingsVec[i].price - thingsVec[i].secondAppendix->price >= 0) ? bag[i - 1][j - thingsVec[i].price - thingsVec[i].secondAppendix->price] + thingsVec[i].price * thingsVec[i].importance + thingsVec[i].secondAppendix->price * thingsVec[i].secondAppendix->importance :0 :0; //放入且兩個附屬物品都放入(對應附屬物品存在並且放得下) int putInWithTwoAppendix = (thingsVec[i].secondAppendix != NULL && thingsVec[i].secondAppendix != NULL) ? (j - thingsVec[i].price - thingsVec[i].firstAppendix->price - thingsVec[i].secondAppendix->price >= 0) ? bag[i - 1][j - thingsVec[i].price - thingsVec[i].firstAppendix->price - thingsVec[i].secondAppendix->price] + thingsVec[i].price * thingsVec[i].importance + thingsVec[i].firstAppendix->price * thingsVec[i].firstAppendix->importance + thingsVec[i].secondAppendix->price * thingsVec[i].secondAppendix->importance :0 :0; bag[i][j] = max({notPutIn,putInWithoutAppendix,putInWithFirstAppendix,putInWithSecondAppendix,putInWithTwoAppendix}); } } cout << (bag[bag.size() - 1][wide.size() - 1]) * 10;//由於之前對價格進行/10操作,因此揹包中資料是實際資料的0.1倍,要在最後還原資料就要再乘以10 return 0; }