南昌航空大学软件学院第一次博客作业
前言:
学习java语言五周了,已经勉强能编写一些简单的java程序。相比上个学期的C语言,感觉C和java还是相差很多的,最主要的是java要比C难挺多,也有可能是先入为主原因导致适应不了Java的面向对象的写法,总是会不经意间写成了面向过程的形式。不过经过一个多月的磨合和训练,还是勉强有点适应了java语言。在Java中万物皆类,万物皆对象,在程序中应该尽量将工作拆分到各个类中写。
在这三次大作业的与Java这个对象磨合过程中可以说是狼狈不堪,不过虽然说作业的难度每一次都在提升,但由于不断的训练,每次的乏力感反而逐渐降低(也许是适应了被Java按在地上摩擦产生的错觉)。
三次大作业中只有第一次简单,后面的都很难,好在同学之间的相互交流和帮助还是最终克服测试点,第一二次都得了满分,第三次有个测试点找了十来个小时直到pta倒计时了也只能放手了,喜提99分,欲哭无泪。大作业难度的话总体还是还行,第一次作业只有一些输入输出,仅仅是对C的过度,还是挺简单的;第二次作业虽然只有四题,但第一二题的四个类的菜单题对于当接触java的我来说显得还是挺难的,第三次有了前一次的经验就好了很多,没有太多的困难。
(1)7-1 菜单计价程序-1
分数 30
全屏浏览题目
切换布局
作者 蔡轲
单位 南昌航空大学
某饭店提供4种菜,每种菜品的基础价格如下:
西红柿炒蛋 15
清炒土豆丝 12
麻婆豆腐 12
油淋生菜 9
设计点菜计价程序,根据输入的订单,计算并输出总价格。
订单由一条或多条点菜记录组成,每条记录一行,最后以"end"结束
每条点菜记录包含:菜名、份额两个信息。
份额可选项包括:1、2、3,分别代表小、中、大份)
不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格2。
如果计算出现小数,按四舍五入的规则进行处理。
参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
}
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
}
点菜记录类:保存订单上的一道菜品记录
Record {
Dish d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
int getPrice()//计价,计算本条记录的价格
}
订单类:保存用户点的所有菜的信息。
Order {
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(String dishName,int portion)
//添加一条菜品信息到订单中。
}
输入格式:
每条点菜记录的格式:
菜名+空格(英文)+份额
注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
最后一条记录以“end”结束。
输出格式:
订单上所有菜品的总价(整数数值),每份菜
如果订单中包含不能识别的菜名,则在总价之前输出“** does not exist”,**是不能识别的菜名
输入样例:
在这里给出一组输入。例如:
麻婆豆腐 2
西红柿炒蛋 3
end
输出样例:
在这里给出相应的输出。例如:
48
输入样例1:
订单中包含不存在的菜品记录。例如:
麻婆豆腐 2
炒脆肚 2
西红柿炒蛋 3
end
输出样例1:
在这里给出相应的输出。例如:
炒脆肚 does not exist
48
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
源码:
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Menu menu = new Menu();
Scanner x = new Scanner(System.in);
String dishName;//菜名
int portion;/1/份额
int totalPrice = 0;//总的钱
while (true)
{
dishName = x.next();//输入菜名
if (dishName.equals("end"))
break;
portion = x.nextInt();//输入份额
Dish dish = menu.searchDish(dishName);//返回查询的结果
if (dish == null)//没有该菜名
{
System.out.println(dishName+" does not exist");
continue;
}
int price = dish.getPrice(portion);//一个菜的钱
totalPrice = totalPrice + price;//总的钱
}
System.out.println(totalPrice);
}
}
class Dish//菜类
{
String name;//菜名属性
int unit_price;//菜价属性
public Dish(String name, int unit_price)
{
this.name = name;
this.unit_price = unit_price;
}
public int getPrice(int portion)//计算一份菜的钱
{
double price = 0;
if (portion == 1)
price = unit_price;
else if (portion == 2)
price = unit_price * 1.5;
else if (portion == 3)
price = unit_price * 2;
return (int) Math.round(price);
}
}
class Menu//菜单类
{
Dish[] dishes;//菜的数组
public Menu()
{
dishes = new Dish[4];
dishes[0] = new Dish("西红柿炒蛋", 15);
dishes[1] = new Dish("清炒土豆丝", 12);
dishes[2] = new Dish("麻婆豆腐", 12);
dishes[3] = new Dish("油淋生菜", 9);
}
public Dish searchDish(String dishName)
{
for (Dish dish : dishes)//循环每一种菜
if (dish.name.equals(dishName))//输入的菜是否在菜单上
return dish;//返回找到的菜名
return null;//没 找到返回空
}
}
(1)设计与分析
解释:
在这道题目中首先通过Menu类将题目所给的四个菜输入进菜单,然后依次输入每个菜的菜名和分量,通过public Dish searchDish(String dishName)查找菜名是否在菜单中,如果菜名在我的Menu中时就计算该项菜所需要的钱并且加入进totalPrice中,如果不存在的就输出该菜名does not exist。然后继续输入下一个菜。如果输入的菜名为end就跳出循环然后输出一共需要的钱,程序结束。
心得:总体来说这道题并不是很难,主要是作为刚写Java的过度题就显得格外的难,通过这道题我逐渐了解了一些Java方法和属性的简单调用,也算是为Java的入门打下了所必须的基础。
(2)踩坑分析
类图:
菜单的第一题逻辑问题相对简单,所以在提交过程中问题一直是处在编译的过程中,没有妥善处理好类与类之间的关系导致报错,在多次的调试后过了编译第一次提交是17分(满分30分)错的测试点如下
发现含异常菜名的测试点都错了,所以通过调试和pta的测试功能重点关注处理错误菜名的部分找出了是个简单的逻辑错误。改正后第二次提交拿到了30分。
(3)主要的困难及改进建议
像上面所说,第一题的困难主要出在编译问题上,还是不熟悉类的方法及属性的调用,题目的逻辑问题上没有什么问题。所以当然也就没有什么改进建议了。
7-2 菜单计价程序-2
分数 40
全屏浏览题目
切换布局
作者 蔡轲
单位 南昌航空大学
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。
菜单由一条或多条菜品记录组成,每条记录一行
每条菜品记录包含:菜名、基础价格 两个信息。
订单分:点菜记录和删除信息。每一类信息都可包含一条或多条记录,每条记录一行。
点菜记录包含:序号、菜名、份额、份数。
份额可选项包括:1、2、3,分别代表小、中、大份。
删除记录格式:序号 delete
标识删除对应序号的那条点菜记录。
不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格2。
如果计算出现小数,按四舍五入的规则进行处理。
参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu { Dish[] dishs ;//菜品数组,保存所有菜品信息 Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。 Dish addDish(String dishName,int unit_price)//添加一道菜品信息}
点菜记录类:保存订单上的一道菜品记录
Record { int orderNum;//序号\ Dish d;//菜品\ int portion;//份额(1/2/3代表小/中/大份)\ int getPrice()//计价,计算本条记录的价格\}
订单类:保存用户点的所有菜的信息。
Order {
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。
delARecordByOrderNum(int orderNum)//根据序号删除一条记录
findRecordByNum(int orderNum)//根据序号查找一条记录
}
输入格式:
菜品记录格式:
菜名+英文空格+基础价格
如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。
点菜记录格式:
序号+英文空格+菜名+英文空格+份额+英文空格+份数
注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
删除记录格式:序号 +英文空格+delete
最后一条记录以“end”结束。
输出格式:
按顺序输出每条订单记录的处理信息,
每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品*份数,序号是之前输入的订单记录的序号。
如果订单中包含不能识别的菜名,则输出“** does not exist”,**是不能识别的菜名
如果删除记录的序号不存在,则输出“delete error”
最后输出订单上所有菜品的总价(整数数值),
本次题目不考虑其他错误情况,如:菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的下一次作业中会做要求。
输入样例:
在这里给出一组输入。例如:
麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
end
输出样例:
在这里给出相应的输出。例如:
1 麻婆豆腐 36
2 油淋生菜 27
63
输入样例1:
订单中包含删除记录。例如:
麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
输出样例1:
在这里给出相应的输出。例如:
1 麻婆豆腐 36
2 油淋生菜 27
27
输入样例2:
订单中包含不存在的菜品记录。例如:
麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
end
输出样例2:
在这里给出相应的输出。例如:
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
63
输入样例3:
订单中包含删除信息以及不存在的菜品记录。例如:
麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
1 delete
7 delete
end
输出样例3:
在这里给出相应的输出。例如:
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
27
输入样例4:
订单中包含删除信息以及不存在的菜品记录。例如:
麻婆豆腐 12
油淋生菜 9
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
5 delete
7 delete
end
输出样例4:
在这里给出相应的输出。例如:
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
delete error;
63
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Menu menu = new Menu();
Scanner x = new Scanner(System.in);
int portion;//份额
int fenshu0;//份数
int[] price=new int[20];//一个菜的钱
String dishName;//菜名
String dishnumber;//序号
int totalPrice = 0;//总的钱
int i=0,j=0;
String name;
while (true)
{
name = x.next();
if (name.equalsIgnoreCase("1"))
break;
if(name.equalsIgnoreCase("end"))
{
System.out.println("0");
return;
}
portion = x.nextInt();
menu.add(name,portion);
}
while (true)
{
i++;
if(i==1)
dishnumber=name;//输入序号
else
dishnumber=x.next();//输入序号
if (dishnumber.equals("end"))
break;
int num=Integer.parseInt(dishnumber);
dishName = x.next();//输入菜名
if(dishName.equalsIgnoreCase("delete"))
{
i--;
price[num-1]=0;
if(num>i)
System.out.println("delete error;");
}
else
{
portion = x.nextInt();//输入份额
fenshu0=x.nextInt();//输入份数
Dish dish = menu.searchDish(menu,dishName);//返回查询的结果
if(dish == null)//没有该菜名
System.out.println(dishName+" does not exist");
else
{
price[num-1] = dish.getPrice(portion)*fenshu0;//一个菜的钱
System.out.println(num+" "+dishName+" "+price[num-1]);
}
}
}
for(i=0;i<20;i++)
totalPrice = totalPrice + price[i];//总的钱
System.out.println(totalPrice);
}
}
class Dish//菜类
{
String name;//菜名属性
int unit_price;//菜价属性
public Dish(String name, int unit_price)
{
this.name = name;
this.unit_price = unit_price;
}
public int getPrice(int portion)//计算一份菜的钱
{
double price = 0;
if (portion == 1)
price = unit_price;
else if (portion == 2)
price = unit_price * 1.5;
else if (portion == 3)
price = unit_price * 2;
return (int) Math.round(price);
}
}
class Menu//菜单类
{
int i=0;
Dish[] dishes=new Dish[20];//菜的数组
public void add(String dishName,int price)
{
dishes[i] = new Dish(dishName,price);
i++;
}
public Dish searchDish(Menu menu,String dishName)
{
for (int j=i-1;j>=0;j--)//循环每一种菜
if (dishes[j].name.equals(dishName))//输入的菜是否在菜单上
return dishes[j];//返回找到的菜名
return null;//没找到返回空
}
}
(1)设计与分析
解释:
这道题是在第二次作业的第一题的基础上加上了一个菜单删除的功能,并且相比原来的固定的四种菜,本题在输出的开头开头用要求自己输入店里有的菜及其价格。关于菜名的输入和保存我在第一题的while(true)语句前面加了一段如下代码
while (true)
{
name = x.next();
if (name.equalsIgnoreCase("1"))
break;
if(name.equalsIgnoreCase("end"))
{
System.out.println("0");
return;
}
portion = x.nextInt();
menu.add(name,portion);
}
该段通过调用Menu类中的public void add(String dishName,int price)方法以实现将菜单保存在Menu类中的Dish[20]属性中。后面的菜名的查找和第一题一样。而该题要求的删除功能直接在主类中加了几句代码if(dishName.equalsIgnoreCase("delete"))
{ i--;
price[num-1]=0;
if(num>i)
System.out.println("delete error;");}
如果输入了delete,就把用于计算订单菜的数量的i减一,并且将该项菜所对应的price[num-1]赋予0,在此基础上如果输入的要删除的num小于订单中菜的数量说明没有所要删除的菜,那么就根据题目要求输出delete error;到此题目要求加的功能就完成了。
心得:
这道题就是在原有的代码上加入一些功能,主要是练习到了代码的增添和修改,而这也是面向对象课程的意义,根据用户的需求对程序不断改进。
(2)踩坑心得
类图:
第二题相比第二题就麻烦了很多,主要是不知道如何把输入的菜单起来等错,反正前后提交了29次才终于达到40分。其中第一次提交的得分是14分
其中大部分错误是非零返回,调试时发现每当输入了异常菜单时就会必会非零返回,然后几经周折和同学指点终于找到原因,当输入的菜名异常时dish =null,而这个dish又在我不知不觉中继续使用了,所以才会报错非零返回。解决完这个非零返回的错误便来到了24分
然后又改了一个小地方得到了26分,最后我们经过不断的测试发现如果输入了两遍相同的菜名但是只有价格不一样时后面输入的菜价应该覆盖前面的,我就干脆将public Dish searchDish(Menu menu,String dishName)
{
for (int j=0;j<i;j++)//循环每一种菜
if (dishes[j].name.equals(dishName))//输入的菜是否在菜单上
return dishes[j];//返回找到的菜名
return null;//没找到返回空
中的for循环改成了for (int j=i-1;j>=0;j--),这样就可以让后面输入的菜价覆盖前面的,然后提交果然得了40分。
(3)主要困难以及改进建议
这道题遇到得困难主要在未查找到菜名返回null而导致非零返回,而在c语言中很少有null的介入,从而这一方面的知识不熟悉,在这个点上出现了长时间的错误。还有就是测试点的意图不太明确,也可能是训练不够没有足够的意识去考虑到这个方面的问题。建议的话从这道题暂时没有什么好的建议。
7-1 菜单计价程序-3
分数 30
全屏浏览题目
切换布局
作者 蔡轲
单位 南昌航空大学
设计点菜计价程序,根据输入的信息,计算并输出总价格。
输入内容按先后顺序包括两部分:菜单、订单,最后以"end"结束。
菜单由一条或多条菜品记录组成,每条记录一行
每条菜品记录包含:菜名、基础价格 两个信息。
订单分:桌号标识、点菜记录和删除信息、代点菜信息。每一类信息都可包含一条或多条记录,每条记录一行或多行。
桌号标识独占一行,包含两个信息:桌号、时间。
桌号以下的所有记录都是本桌的记录,直至下一个桌号标识。
点菜记录包含:序号、菜名、份额、份数。份额可选项包括:1、2、3,分别代表小、中、大份。
不同份额菜价的计算方法:小份菜的价格=菜品的基础价格。中份菜的价格=菜品的基础价格1.5。小份菜的价格=菜品的基础价格2。如果计算出现小数,按四舍五入的规则进行处理。
删除记录格式:序号 delete
标识删除对应序号的那条点菜记录。
如果序号不对,输出"delete error"
代点菜信息包含:桌号 序号 菜品名称 份额 分数
代点菜是当前桌为另外一桌点菜,信息中的桌号是另一桌的桌号,带点菜的价格计算在当前这一桌。
程序最后按输入的先后顺序依次输出每一桌的总价(注意:由于有代点菜的功能,总价不一定等于当前桌上的菜的价格之和)。
每桌的总价等于那一桌所有菜的价格之和乘以折扣。如存在小数,按四舍五入规则计算,保留整数。
折扣的计算方法(注:以下时间段均按闭区间计算):
周一至周五营业时间与折扣:晚上(17:00-20:30)8折,周一至周五中午(10:30--14:30)6折,其余时间不营业。
周末全价,营业时间:9:30-21:30
如果下单时间不在营业范围内,输出"table " + t.tableNum + " out of opening hours"
参考以下类的模板进行设计:菜品类:对应菜谱上一道菜的信息。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) }
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish\[\] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
Dish addDish(String dishName,int unit_price)//添加一道菜品信息
}
点菜记录类:保存订单上的一道菜品记录
Record {
int orderNum;//序号\\
Dish d;//菜品\\
int portion;//份额(1/2/3代表小/中/大份)\\
int getPrice()//计价,计算本条记录的价格\\
}
订单类:保存用户点的所有菜的信息。
Order {
Record\[\] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(int orderNum,String dishName,int portion,int num)//添加一条菜品信息到订单中。
delARecordByOrderNum(int orderNum)//根据序号删除一条记录
findRecordByNum(int orderNum)//根据序号查找一条记录
}
### 输入格式:
桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)
菜品记录格式:
菜名+英文空格+基础价格
如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。
点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
删除记录格式:序号 +英文空格+delete
代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数
最后一条记录以“end”结束。
### 输出格式:
按输入顺序输出每一桌的订单记录处理信息,包括:
1、桌号,格式:table+英文空格+桌号+”:”
2、按顺序输出当前这一桌每条订单记录的处理信息,
每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名
如果删除记录的序号不存在,则输出“delete error”
最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
输入格式:
桌号标识格式:table + 序号 +英文空格+ 日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)
菜品记录格式:
菜名+英文空格+基础价格
如果有多条相同的菜名的记录,菜品的基础价格以最后一条记录为准。
点菜记录格式:序号+英文空格+菜名+英文空格+份额+英文空格+份数注:份额可输入(1/2/3), 1代表小份,2代表中份,3代表大份。
删除记录格式:序号 +英文空格+delete
代点菜信息包含:桌号+英文空格+序号+英文空格+菜品名称+英文空格+份额+英文空格+分数
最后一条记录以“end”结束。
输出格式:
按输入顺序输出每一桌的订单记录处理信息,包括:
1、桌号,格式:table+英文空格+桌号+“:”
2、按顺序输出当前这一桌每条订单记录的处理信息,
每条点菜记录输出:序号+英文空格+菜名+英文空格+价格。其中的价格等于对应记录的菜品\*份数,序号是之前输入的订单记录的序号。如果订单中包含不能识别的菜名,则输出“\*\* does not exist”,\*\*是不能识别的菜名
如果删除记录的序号不存在,则输出“delete error”
最后按输入顺序一次输出每一桌所有菜品的总价(整数数值)格式:table+英文空格+桌号+“:”+英文空格+当前桌的总价
本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。
输入样例:
在这里给出一组输入。例如:
麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 12/2/3
1 麻婆豆腐 2 2
2 油淋生菜 1 3
end
输出样例:
在这里给出相应的输出。例如:
table 1:
1 麻婆豆腐 36
2 油淋生菜 27
table 1: 38
输入样例1:
在这里给出一组输入。例如:
麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 17/0/0
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
输出样例1:
在这里给出相应的输出。例如:
table 1:
1 麻婆豆腐 36
2 油淋生菜 27
table 1: 22
输入样例2:
在这里给出一组输入。例如:
麻婆豆腐 12
油淋生菜 9
table 1 2023/3/22 16/59/59
1 麻婆豆腐 2 2
2 油淋生菜 1 3
1 delete
end
输出样例2:
在这里给出相应的输出。例如:
table 1:
1 麻婆豆腐 36
2 油淋生菜 27
table 1 out of opening hours
输入样例3:
在这里给出一组输入。例如:
麻婆豆腐 12
油淋生菜 9
table 1 2022/12/5 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
5 delete
7 delete
table 2 2022/12/3 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
7 delete
end
输出样例3:
在这里给出相应的输出。例如:
table 1:
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
delete error;
table 2:
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
delete error;
table 1 out of opening hours
table 2: 63
输入样例4:
在这里给出一组输入。例如:
麻婆豆腐 12
油淋生菜 9
table 1 2022/12/3 19/5/12
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
table 2 2022/12/3 15/03/02
1 麻婆豆腐 2 2
2 油淋生菜 1 3
3 麻辣鸡丝 1 2
1 4 麻婆豆腐 1 1
7 delete
end
输出样例4:
在这里给出相应的输出。例如:
table 1:
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
table 2:
1 麻婆豆腐 36
2 油淋生菜 27
麻辣鸡丝 does not exist
4 table 2 pay for table 1 12
delete error;
table 1: 63
table 2: 75
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
import java.util.*;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Main
{
public static void main(String[] args)
{
Menu menu = new Menu();
date dd = new date();
Discount dc=new Discount();
Table[] ta =new Table[5];
Scanner x = new Scanner(System.in);
int portion;//份额
int fenshu0;//份数
int[] price=new int[10];//一个菜的钱
String dishName;//菜名
String dishnumber;//序号
int totalPrice = 0;//总的钱
int dayofweek;//当周第几天
int i=0,j=0,t=0;
String name;
while (true)
{
name = x.next();
if (name.equalsIgnoreCase("table"))
break;
if(name.equalsIgnoreCase("end"))
return;
portion = x.nextInt();
menu.add(name,portion);
}
while(true)
{
t=x.nextInt();
ta[t-1]=new Table();String DATE=x.next();//输入日期
int day=dd.getDayOfWeek(DATE);
String TIME=x.next();//输入时间
ta[t-1].discount=dc.getdiscountoftime(day,TIME);
System.out.println("table "+t+": ");
if(t!=1)
while (true)
{
name = x.next();
if (name.equalsIgnoreCase("1"))
break;
if(name.equalsIgnoreCase("end"))
return;
portion = x.nextInt();
menu.add(name,portion);
}
i=0;
while (true)
{
i++;
if(t==1||((t!=1)&&i!=1))
dishnumber=x.next();//输入序号
else
dishnumber=String.valueOf(1);
if (dishnumber.equals("end")||dishnumber.equals("table"))
break;
int num=Integer.parseInt(dishnumber);
dishName = x.next();//输入菜名
if(dishName.equalsIgnoreCase("delete"))
{
i--;
price[num-1]=0;
if(num>i)
System.out.println("delete error;");
}
else
{
if(dishName.equalsIgnoreCase(String.valueOf(i)))
{
dishName = x.next();
portion = x.nextInt();//输入份额
fenshu0=x.nextInt();//输入份数
Dish dish = menu.searchDish(menu,dishName);//返回查询的结果
if(dish == null)//没有该菜名
System.out.println(dishName+" does not exist");
else
{
price[i-1] = dish.getPrice(portion)*fenshu0;//一个菜的钱
System.out.println(i+" table "+t+" pay for table "+dishnumber+" "+price[i-1]);
}
}
else
{
portion = x.nextInt();//输入份额
fenshu0 = x.nextInt();//输入份数
Dish dish = menu.searchDish(menu, dishName);//返回查询的结果
if (dish == null)//没有该菜名
System.out.println(dishName + " does not exist");
else
{
price[num - 1] = dish.getPrice(portion) * fenshu0;//一个菜的钱
System.out.println(num + " " + dishName + " " + price[num - 1]);
}
}
}
}
for(i=0;i<10;i++)
{
ta[t-1].totalprice = ta[t-1].totalprice + price[i];//总的钱
price[i]=0;
}
if (dishnumber.equals("end"))
break;
}
for(i=0;i<t;i++)
{
if(ta[i].discount==11)
System.out.printf("table %d out of opening hours\n",i+1);
else
System.out.println("table "+(i+1)+": "+Math.round(ta[i].totalprice*ta[i].discount/10.0));
}
}
}
class Dish//菜类
{
String name;//菜名属性
int unit_price;//菜价属性
public Dish(String name, int unit_price)
{
this.name = name;
this.unit_price = unit_price;
}
public int getPrice(int portion)//计算一份菜的钱
{
double price = 0;
if (portion == 1)
price = unit_price;
else if (portion == 2)
price = unit_price * 1.5;
else if (portion == 3)
price = unit_price * 2;
return (int) Math.round(price);
}
}
class Menu//菜单类
{
int i=0;
Dish[] dishes=new Dish[10];//菜的数组
public void add(String dishName,int price)
{
dishes[i] = new Dish(dishName,price);
i++;
}
public Dish searchDish(Menu menu,String dishName)
{
for (int j=i-1;j>=0;j--)//循环每一种菜
if (dishes[j].name.equals(dishName))//输入的菜是否在菜单上
return dishes[j];//返回找到的菜名
return null;//没找到返回空
}
}
class date
{
public int getDayOfWeek(String DATE)// 获取周第几天
{
String[] strings=DATE.split("/");
int[] Tentime=new int [3];
for(int i=0;i<3;i++)
Tentime[i]=Integer.parseInt(strings[i]);
LocalDate date1 = LocalDate.of(Tentime[0],Tentime[1],Tentime[2]);
return (date1.getDayOfWeek().getValue());
}
}
class Discount
{
public int getdiscountoftime(int ddd,String time)
{
int tentime;
int[] Tentime=new int [3];
String[] strings=time.split("/");
for(int i=0;i<3;i++)
Tentime[i]=Integer.parseInt(strings[i]);
tentime=Tentime[0]*3600+Tentime[1]*60+Tentime[2];
if((tentime>=10.5*3600&&tentime<=14.5*3600)&&(ddd>=1&&ddd<=5))
return 6;
else if((tentime>=17*3600&&tentime<=20.5*3600)&&(ddd>=1&&ddd<=5))
return 8;
else if((tentime>=9.5*3600&&tentime<=21.5*3600)&&(ddd==6||ddd==7))
return 10;
else
return 11;
}
}
class Table
{
int discount;
int totalprice;
}
(1)设计与分析
解释:
在这道题中主要是在上一次作业的7-2的救出上引入了一个桌和打折的概念,代码中可以实现几桌一起点菜甚至帮别的桌点菜然后付这个菜的钱。而且在不同时间点菜可以有不同折扣,也会有店不在营业时间的情况。在加入桌这个概念时我主要是加入了一个Table类,他里面仅包括discount和totalprice两个属性,分别用于计算每桌的折扣和总价。另外我还添加了一个date类用于获取输入日期的周数,还有一个Discount类中的public int getdiscountoftime(int ddd,String time)方法用于计算对应情况的折扣,在这个方法除了返回11对应的是不在营业时间其他的都是返回对应时间的折扣数。在点菜时每行的第二个本应该输入菜的名字,但如果输入的菜名为table时说明是要为别人点菜了,然后根据这种不一样的输入写在一个if语句里从而实现为别人点菜。除此之外,在输出每一桌的总消费时加入了如下一个if语句
if(ta[i].discount==11)
System.out.printf("table %d out of opening hours\n",i+1);
else
System.out.println("table "+(i+1)+": "+Math.round(ta[i].totalprice*ta[i].discount/10.0));
用于实现discount的折扣功能,到此这道题要求加入的功能就差不多结束了,代码量直接翻了一番。
心得:
相比第二题在第一题基础上加的功能,这道题显然复杂很多,而在代码功能慢慢复杂的时候,要紧扣Main类和各个类之间的关系还有各个类之间的依赖和组合等关系,明确每个类的职责正是面向对象程序设计的核心。
(2)踩坑心得
类图:
在经历了第二道题的洗礼之后就习惯了很多,这道题的修改思路也比较明确,在根据要求加完所需功能后就来到了17分,
得了17分到这里就不知道怎么改了,因为测试样例5在编译器上能正常运行而在pta上超时就是代码复杂度问题了,后来知道用于获取星期的Calendar的需要大量时间,把这个修改成了另一种时间复杂度更少的LocalDate就一下减了100多ms然后进行了一些别的简单修改,不过这时还是只有23分
在这之后我又进行了大量的测试样例的一小部分的修改用于找到这三个多桌菜的测试点,发现当仅仅只把周末晚上关门时间改成21.30时,23分就变成了29分,其他这么改的同学这三个测试点也全对了,当时觉得有可能是故意出一个错误时间考验我们。后来才知道是这个题目错了,周末关门时间就是21.30。然后他们在我告诉他们之后他们都是30分就我还差个测试点14,然后又进行了许多测试和修改几乎要把这个测试点的输入都要找出来了,对着改,还是错的,最后只能眼睁看着倒计时无奈喜提29分。也正因为这两个原因这一题的提交次数达到了恐怖的182。
(3)主要困难以及改进建议
主要困难:
获取日期的方法的函数时间复杂度太高,导致一段时间不知道代码如何改进。关门时间出错,导致把正确时间测出花了大量时间。第十四个测试点测了十来个小时明明把它想要测试的点全找出来了对着修改还是错的
改进建议:希望作业结束的时候可以有机会选择一两个测试点看它的输入数据,这样就不会像我的14个测试点一样“死不瞑目”了。
总结:
总的来说这三次作业还是学到了也锻炼到了很多,我现在已经可以较为熟练的调用类里面的方法和属性,调整类与类的关系,在三次作业之前还是对Java一窍不通现在已经能写一些简单的程序并且在上面逐渐加一些功能,代码的复杂程度也在慢慢提高。理论课的作用总是有限的,通过自己的练习才能有大的提高,大作业是一个很好的学习途径帮助我们完善自己的代码漏洞,找到自己的不足之处。同学之间可以互相讨论相互学习增加任务效率和质量。而且也没有人会抄别人的代码混过去它也起到一个好的监督作用,大作业不写就没分得挂科。认真对待每一次大作业,Java程序的编写能力一定会有很大提高。
改进建议的话还是希望作业结束后能选择看一两个测试点的输入内容,有个别测试点真的是找了十来个小时都找不出来的确实没办法,如果结束之后能看到输入的话感觉对以后的测试点的查找的开阔性思维有一点启发作用吧。而且花了太多时间没找到原因最后还是无法知道确实有一点浪费时间的感觉在里面吧。