1. 程式人生 > 實用技巧 >20200718阿里筆試第二題

20200718阿里筆試第二題


題目2:包粽子, 四個數n, m, c0, d0, 一共n 克麵粉, m種餡料

然後m行,每行四個數ai, bi, ci, di, ai 表示一共多少克該種餡料 每個粽子包法, bi克第i種餡料 + ci 克麵粉, 收益di, 或者 c0 克麵粉, 不包餡料, 收益d0 求最大收益

參加了阿里筆試,第一題沒看懂,第二題寫了半天,使用的遞迴求解,思路沒問題,但是遞迴顯然時間複雜度會很大,因此只通過20%的用例,之後就超出時間限制了,

對於遞迴窮舉的問題我們都可以使用動態規劃來大大降低他的時間複雜度,通過構建陣列這個空間來優化

由於在考試的時候,看到題比較懵,題目資訊有點小大,理解了一段時間,直接按照遞迴的思路來分析了,因此使用遞迴來解得

考完試後我苦思冥想,這道題動態規劃該怎麼寫呢?於是今天早上起來我想了一下演算法,寫著寫著,發現了這道題不僅僅需要動態規劃,還需要貪心演算法來解答,可惜考試中沒想到,因此我現在也沒有示例了,只有考試中的一個示例,跑的結果沒問題,我覺得我的思路很正確,就是寫的太繁瑣了,來記錄一下,順便分享一下,如果我的思路能夠幫助小夥伴的話,那就更好了,對於遞迴求解法這裡我把我寫的程式碼貼上上,思路就不講解了,畢竟時間複雜度比較大,這裡我重點說一下動態規劃+貪心演算法,我是如何思考的,當然僅供參考

遞迴求解的程式碼貼出來:

import java.util.ArrayList;
import java.util.Scanner;

public class Test { static int maxValue=-1; public static void main(String[] args) { Scanner s=new Scanner(System.in); String[] ones=s.nextLine().split(" "); if(ones.length!=4)return; int n=Integer.parseInt(ones[0]),m=Integer.parseInt(ones[1]),c0=Integer.parseInt(ones[2]),d0=Integer.parseInt(ones[3]); String[][] others
=new String[m][4]; for(int i=0;i<m;i++){ others[i]=s.nextLine().split(" "); } //將輸入的轉化為數字型列表,方便回溯 ArrayList<ArrayList<Integer>> lists=new ArrayList<>(); ArrayList<Integer> temp; for(int i=0;i<m;i++){ temp=new ArrayList<>(); for(int j=0;j<4;j++){ temp.add(Integer.parseInt(others[i][j])); } lists.add(temp); } //(這裡其實可以全部放到下面的) //回溯遞迴,每一個我做0個到做大最大可做的數量,每一個我都嘗試,剩餘的給其他的,達到深度搜索 getMax(lists,n,0,c0,d0); System.out.println(maxValue); } /** * * @param lists * @param restMian 剩餘麵粉數量 * @param money 當前積累價值 * @param c0 消耗c0麵粉 * @param d0 產生d0價值 */ private static void getMax(ArrayList<ArrayList<Integer>> lists,int restMian,int money,int c0,int d0){ //判斷當前lists裡面還有沒有,如果沒有了,則我計算剩餘麵粉的價值加上後和現有的最大值比較 if(lists.isEmpty()){ int curMax= money+(restMian/c0)*d0; if(maxValue<curMax){ maxValue=curMax;} } //如果還有,則我們還得按照方案繼續分配 ArrayList<Integer> temp; int tempMoney; for (int i = 0; i < lists.size(); i++) { temp=new ArrayList<>(); //本種類做0次到可做的最大次 tempMoney=money; for(int j=0;j<=lists.get(i).get(0)/lists.get(i).get(1);j++){ //需要判斷當前來做麵粉夠不夠,只有夠了,才能操作 tempMoney=money; int te=restMian-lists.get(i).get(2)*j; if(te>0){ tempMoney+=lists.get(i).get(3)*j; temp=lists.get(i); lists.remove(lists.get(i)); getMax(lists,te,tempMoney,c0,d0); lists.add(0,temp); } } } }
遞迴求解程式碼