分享一下我老师大神的人工智能教程!零基础,通俗易懂!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日补充
///////////////////////////////