滴滴打車2017招聘筆試題
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
有個一個飯店,有n張桌子,每張桌子可以招待不同數量的客人,且不能拼桌,現在來了m批客人,每批客人有兩個屬性,一個是客人的總數,一個是他們消費(預計)的總額
請設計一個演算法,計算出,店家能夠獲得的最大利潤
我自己設計了一個演算法,是這麼思考的,先把客人排序,按照消費比(就是消費的金額除以人數)排序,然後吧桌子也排序
首先安排消費比最高的客人,從最小的桌子開始安排,如果桌子太小了,就換一個比它大一點的桌子
程式碼如下:
import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Scanner;class Table2 implements Comparable<Table2>{ int m; boolean used; int fee; public Table2(int count){ m=count; } @Override public int compareTo(Table2 o) { if (o.m>=m) { return -1; }else { return 1; } }}class Person implements Comparable <Person>{ int count; int fee; double rate; boolean zhaodai; public void computeRate(){ rate=fee*1.0/count; } public Person(int count,int fee){ this.count=count; this.fee=fee; } @Override public int compareTo(Person o) { if (o.rate>=rate) { return 1; }else { return -1; } } public String toString(){ return count+" "+" "+fee+" "+rate; }}public class Main { public static void main(String[] args) { int n,m; Scanner sc=new Scanner(System.in); n=sc.nextInt(); m=sc.nextInt(); List<Table2> nList=new ArrayList<>(); for (int i = 0; i < n; i++) { Table2 table=new Table2(sc.nextInt()); nList.add(table); } Collections.sort(nList); List<Person> pList=new ArrayList<>(); for (int i = 0; i < m; i++) { Person person=new Person(sc.nextInt(),sc.nextInt()); person.computeRate(); pList.add(person); } Collections.sort(pList);// for (int i = 0; i < pList.size(); i++) {// System.out.println(pList.get(i));// } for (int i = 0; i < pList.size(); i++) { Person person=pList.get(i); if (!person.zhaodai) { for (int j = 0; j < nList.size(); j++) { Table2 t=nList.get(j); if (!t.used) { if (person.count<t.m) { t.used=true; t.fee=person.fee; person.zhaodai=true; break; } } } } } int sum=0; for (int j = 0; j < nList.size(); j++) { Table2 t=nList.get(j); sum+=t.fee; } System.out.println(sum); }}/*3 52 4 21 33 53 75 9 1 10 */
上面的測試用例
3 5代表一共有3個桌子 5批客人
2 4 2 代表3張桌子的容量 分別是2 4 2
後面的1 3 代表第一批客人是1個人 消費3元 然後是第二批客人,共3人消費5元
這個測試用例 最後的答案是20
這個思路,是很直觀的,但是,我沒辦法判斷它的正確性
其實它是錯的
輸入:
1 2
4
2 4
3 5
輸出:
4
可答案應該是5才對,因為題目要求的是總消費最高
感謝網友yg33717
後來,西安交大的張晨同學說,咱們用遞迴試試
思想就是 我隨意讓一個客人佔用一張桌子(當然,至少客人得坐得下)計算一下收益率,然後把剩下的人和剩下的桌子遞迴呼叫安排的程式碼,就OK
我和我的小夥伴們都驚呆了,還能這麼寫
然後 過了20分鐘,他給我發來這個下面的程式碼
import java.util.ArrayList;import java.util.Scanner;/** * Created by zhangchen([email protected]) on 2016/9/7. */public class TableGuest { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int tableCount = 0; int groupCount = 0; while (scanner.hasNextLine()) { tableCount = scanner.nextInt(); groupCount = scanner.nextInt(); ArrayList<Table> tables = new ArrayList<>(); ArrayList<GuestGroup> groups = new ArrayList<>(); for (int i = 0; i < tableCount; i++) { tables.add(new Table(scanner.nextInt())); } for (int j = 0; j < groupCount; j++) { groups.add(new GuestGroup(scanner.nextInt(), scanner.nextInt())); } int maxMoney = getMaxMoney(tables, groups); System.out.println(maxMoney); } } public static int getMaxMoney(ArrayList<Table> tables, ArrayList<GuestGroup> groups) { boolean[] isTableEmpty = new boolean[tables.size()]; boolean[] isGroupWait = new boolean[groups.size()]; for (int i = 0; i < isTableEmpty.length; i++) { isTableEmpty[i] = true; } for (int j = 0; j < isGroupWait.length; j++) { isGroupWait[j] = true; } int maxMoney = assignTable(tables, groups, isTableEmpty, isGroupWait, tables.size(), groups.size()); return maxMoney; } public static int assignTable(ArrayList<Table> tables, ArrayList<GuestGroup> groups, boolean[] isTableEmpty, boolean[] isGroupWait, int tableLeft, int groupLeft) { if (tableLeft == 0 || groupLeft == 0) { return 0; } int[][] values = new int[tables.size()][groups.size()];// 第i行j列表示將table // i分配給group j // 產生的價值 for (int i = 0; i < tables.size(); i++) { for (int j = 0; j < groups.size(); j++) { Table table = tables.get(i); GuestGroup group = groups.get(j); if (isTableEmpty[i] && isGroupWait[j] && table.getCapacity() >= group.getGuestCount()) { // 可以嘗試分配 boolean[] isTableEmptyCurrent = isTableEmpty.clone(); boolean[] isGroupWaitCurrent = isGroupWait.clone(); isTableEmptyCurrent[i] = false; isGroupWaitCurrent[j] = false; values[i][j] = group.getMoney() + assignTable(tables, groups, isTableEmptyCurrent, isGroupWaitCurrent, tableLeft - 1, groupLeft - 1); } } } int maxMoney = 0; for (int i = 0; i < tables.size(); i++) { for (int j = 0; j < groups.size(); j++) { if (values[i][j] > maxMoney) { maxMoney = values[i][j]; } } } return maxMoney; }}class Table { public Table(int capacity) { this.capacity = capacity; } public int getCapacity() { return capacity; } public void setCapacity(int capacity) { this.capacity = capacity; } private int capacity;}class GuestGroup { public GuestGroup(int guestCount, int money) { this.money = money; this.guestCount = guestCount; } private int guestCount; private int money; public int getGuestCount() { return guestCount; } public void setGuestCount(int guestCount) { this.guestCount = guestCount; } public int getMoney() { return money; }}
過了一會,他又說,夥計,夥計,我又有了新的想法,
有一個二維矩陣,m[i][j]=k表示第i這個桌子招待第j批客人,獲得的收益是k元
然後,這個矩陣的每一行,每一列都只能選一個元素
最後求最大值
他問我:你不覺得這程式碼,很熟悉麼?
我看了看,恩,感覺有點像八皇后問題,對呀,他把所有符合規則的排練都求出來,找出最大的 不就OK了麼
子曰:子曰:不憤不啟,不悱不發.舉一隅不與三隅反,則不復也
張晨自己能把這個問題聯絡到八皇后上,牛逼呀
賢哉,晨也!
程式碼如下:
import java.util.ArrayList;import java.util.HashMap;import java.util.Map.Entry;import java.util.Scanner;/** * Created by zhangchen([email protected]) on 2016/9/7. */public class TableGuest2 { public static void main(String[] args){ Scanner scanner=new Scanner(System.in); int tableCount=0; int groupCount=0; while(scanner.hasNextLine()){ tableCount=scanner.nextInt(); groupCount=scanner.nextInt(); ArrayList<Table> tables=new ArrayList<>(); ArrayList<GuestGroup> groups=new ArrayList<>(); for(int i=0;i<tableCount;i++){ tables.add(new Table(scanner.nextInt())); } for(int j=0;j<groupCount;j++){ groups.add(new GuestGroup(scanner.nextInt(),scanner.nextInt())); } int[][] assignmentMatrix=new int[tables.size()][groups.size()]; //將問題轉化為在一個矩陣中,每行選擇一個元素,這些元素不能在同一列,使得和最大 for(int i=0;i<tables.size();i++){ for(int j=0;j<groups.size();j++){ Table table=tables.get(i); GuestGroup group=groups.get(j); if(table.getCapacity() >= group.getGuestCount()){ assignmentMatrix[i][j] = group.getMoney(); //可以獲利 }else { //不能分配 assignmentMatrix[i][j]=0; } } }// int maxMoney= getMaxMoney(tables, groups); int maxMoney= getMaxMoney(assignmentMatrix); System.out.println(maxMoney); } } public static int getMaxMoney(ArrayList<Table> tables, ArrayList<GuestGroup> groups){ boolean[] isTableEmpty=new boolean[tables.size()]; boolean[] isGroupWait=new boolean[groups.size()]; for(int i=0;i<isTableEmpty.length;i++){ isTableEmpty[i]=true; } for(int j=0;j<isGroupWait.length;j++){ isGroupWait[j]=true; } HashMap<Integer,Integer> bestAssignment=assignTable(tables,groups,isTableEmpty,isGroupWait,tables.size(),groups.size()); for(Entry<Integer,Integer> assign:bestAssignment.entrySet()){ System.out.println("將第"+assign.getKey()+"桌分配給"+assign.getValue()+"組客戶"); } return calculateMoney(groups,bestAssignment); } public static int getMaxMoney(int[][] assignmengMatrix){ int rowCount=assignmengMatrix.length; int colCount=assignmengMatrix[0].length; ArrayList<int[]> results=new ArrayList<>(); assignTable(0,new int[rowCount],rowCount,colCount,results); int maxMoney=0; int[] bestAssignment = new int[rowCount]; for(int[] columns:results){ int total=0; for(int row=0;row<rowCount;row++){ total+=assignmengMatrix[row][columns[row]]; } if(total>maxMoney){ maxMoney=total; bestAssignment=columns; } } for(int i=0;i<bestAssignment.length;i++){ System.out.println("將第"+i+"桌分配給"+bestAssignment[i]+"組客戶"); } return maxMoney; } public static void assignTable(int row,int[] columns,int rowCount,int colCount,ArrayList<int[]> results){ if(row == rowCount){//找到有效的分配方案 results.add(columns.clone()); }else{ for(int col=0;col<colCount;col++){ if(checkValid(columns,row,col)){ //分配是否有效 columns[row]=col; //分配桌子 assignTable(row+1,columns,rowCount,colCount,results); } } } } public static boolean checkValid(int[] columns,int row1,int col1){ for(int row2=0;row2<row1;row2++){ int col2=columns[row2]; if(col2==col1){ //某一組客戶被重複分配 return false; } } return true; } public static HashMap<Integer,Integer> assignTable(ArrayList<Table> tables, ArrayList<GuestGroup> groups,boolean[] isTableEmpty,boolean[] isGroupWait,int tableLeft,int groupLeft){ HashMap<Integer,Integer> bestAssignment=new HashMap<>(); if(tableLeft==0 || groupLeft ==0 ){ return bestAssignment; } int maxMoney=0; for(int i=0;i<tables.size();i++){ for(int j=0;j<groups.size();j++){ Table table=tables.get(i); GuestGroup group=groups.get(j); if(isTableEmpty[i] && isGroupWait[j] && table.getCapacity()>=group.getGuestCount()){ //可以嘗試分配 boolean[] isTableEmptyCurrent=isTableEmpty.clone(); boolean[] isGroupWaitCurrent=isGroupWait.clone(); isTableEmptyCurrent[i]=false; isGroupWaitCurrent[j]=false; HashMap<Integer,Integer> assighment=assignTable(tables, groups, isTableEmptyCurrent, isGroupWaitCurrent,tableLeft-1,groupLeft-1); assighment.put(i,j); int money=calculateMoney(groups,assighment); if(money>maxMoney){ bestAssignment=assighment; maxMoney=money; } } } } return bestAssignment; } public static int calculateMoney(ArrayList<GuestGroup> groups,HashMap<Integer,Integer> assignment){ int total=0; for(int groupIndex:assignment.values()){ total+=groups.get(groupIndex).getMoney(); } return total; }}
///////////////////////////////
以下為2016-9-14日補充
感謝"麥爾"對我文章的研究:
非常簡單的問題,怎麼搞得這麼複雜,說明你的演算法功底還很弱,繼續加油學習哦,去TopCoder刷刷題
這個題如果你想到按個人消費排序你就完了,它要的收益最大,不在乎讓最多的人就餐。
演算法思路:
1.將總消費讓從大到小排序 -- consume[m]
2.將桌子按容納人數從小到大排序 -- capacity[n]
3.遍歷consume[m],取出元素後,再從capacity[n]中找到大於或等於該元素人數的桌子,並在capacity[n]標記該桌已用,若沒有桌子能容納該批客則直接放棄該批客人。
就這麼簡單,考慮的是盈利最大,不是要考慮讓更多的人就餐
最後想說我是一個三本學生...
哎怎麼說呢,感覺讀書把自己讀傻了,這個問題本來就很生活化,回家問我不懂計算機的老媽,她估計都能想到這個方法,
我們這些研究生生卻想到那麼複雜的解法,真是讀書讀傻了,這是智商問題呀
以上為2016-9-14日補充
///////////////////////////////