PTA题目集4、5、6以及期中考试的总结性Blog

发布时间 2023-11-19 17:20:37作者: 君御可莉

一.前言

        大三上学期开始,我们开始接触java这门语言,Java具有大部分编程语言所共有的一些特征,被特意设计用于互联网的分布式环境。Java具有类似于C++语言的形式和感觉,但它要比C++语言更易于使用,而且在编程时彻底采用了一种以对象为导向的方式。

       pta已经写了六次了,除了第一次题目难度比较简单,后面的数次难度激增。总体来说,最近pta的主要知识点还是在设计类和学习java语言,以及用面向对象的思维方式。对只接触过一点java语言的我来说还是很有挑战的。这三次pta题目相像,但是难度很大,每次都有菜单的设计,也有很多类的调用,十分复杂,还需要使用很多函数,要有继承和传参,这确实十分困难。

 

二.设计与分析:

第四次题目集:

设计点菜计价程序,根据输入的信息,计算并输出总价格。

输入内容按先后顺序包括两部分:菜单、订单,最后以"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+英文空格+桌号+“:”+英文空格+当前桌的总价

本次题目不考虑其他错误情况,如:桌号、菜单订单顺序颠倒、不符合格式的输入、序号重复等,在本系列的后续作业中会做要求。

 

注意:由于此次pta较难的题目还是菜单计价3,所以只讨论该题,且该题代码在之后并没有沿用下来,所以也不做过多讨论,这里只展示代码

import java.util.*;

public  class Main {
    private static final double DISCOUNT_WEEKDAY_EVENING = 0.8;
    private static final double DISCOUNT_WEEKDAY_NOON = 0.6;
    private static final double DISCOUNT_WEEKEND = 1.0;
    static Map<String, Double> prices = new HashMap<>();
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        Map<String, List<OrderItem>> orders = new HashMap<>();
        

        String line;
        while (!(line = scanner.nextLine().trim()).equals("end")) {
            if (line.isEmpty()) {
                continue;
            }

            String[] fields = line.split("\\s+");
            if (fields.length < 2) {
                continue;
            }

            String type = fields[0];
            if (type.equals("菜单")) {
                // 处理菜单
                String name = fields[1];
                double price = Double.parseDouble(fields[2]);
                prices.put(name, price);
            } else if (type.equals("桌号")) {
                // 处理订单
                String tableNum = fields[1];
                String time = fields[2];
                List<OrderItem> orderItems = new ArrayList<>();
                orders.put(tableNum, orderItems);

                double discount = getDiscount(time);

                while (!(line = scanner.nextLine().trim()).equals("")) {
                    fields = line.split("\\s+");
                    if (fields.length < 2) {
                        continue;
                    }

                    String cmd = fields[1];
                    if (cmd.equals("delete")) {
                        // 处理删除指令
                        int index = Integer.parseInt(fields[0]) - 1;
                        if (index < 0 || index >= orderItems.size()) {
                            System.out.println("delete error");
                        } else {
                            orderItems.remove(index);
                        }
                    } else {
                        // 处理点菜记录
                        String name = fields[1];
                        int portion = Integer.parseInt(fields[2]);
                        int count = Integer.parseInt(fields[3]);
                        OrderItem item = new OrderItem(name, portion, count);
                        orderItems.add(item);
                    }
                }

                // 处理代点菜信息
                while (!(line = scanner.nextLine().trim()).equals("")) {
                    fields = line.split("\\s+");
                    if (fields.length < 5) {
                        continue;
                    }

                    String otherTableNum = fields[0];
                    int index = Integer.parseInt(fields[1]) - 1;
                    String name = fields[2];
                    int portion = Integer.parseInt(fields[3]);
                    int count = Integer.parseInt(fields[4]);
                    double price = prices.get(name) * getPortionRate(portion);
                    OrderItem item = new OrderItem(name, portion, count, price);
                    orders.get(tableNum).add(item);
                }

                // 输出该桌总价
                double totalPrice = 0;
                for (OrderItem item : orderItems) {
                    totalPrice += item.getPrice() * item.getCount();
                }
                totalPrice *= discount;
                System.out.println("桌号 " + tableNum + " 总价:" + Math.round(totalPrice));

            }
        }
    }

    private static double getPortionRate(int portion) {
        switch (portion) {
            case 1:
                return 1.0;
            case 2:
                return 1.5;
            case 3:
                return 2.0;
            default:
                return 1.0;
        }
    }

    private static double getDiscount(String time) {
        Scanner scanner = new Scanner(time);
        scanner.useDelimiter(":");
        int hour = scanner.nextInt();
        int minute = scanner.nextInt();
        scanner.close();

        boolean isWeekend = isWeekend(time);

        if (!isWeekend && hour >= 10 && hour <= 14 && minute >= 30 && minute <= 59) {
            return DISCOUNT_WEEKDAY_NOON;
        } else if (!isWeekend && hour >= 17 && hour <= 20 && minute >= 0 && minute <= 59) {
            return DISCOUNT_WEEKDAY_EVENING;
        } else if (isWeekend && hour >= 9 && hour <= 21 && minute >= 30 && minute <= 59) {
            return DISCOUNT_WEEKEND;
        } else {
            return 0;
        }
    }

    private static boolean isWeekend(String time) {
        Scanner scanner = new Scanner(time);
        scanner.useDelimiter(" ");
        String weekday = scanner.next();
        scanner.close();

        return weekday.equals("星期六") || weekday.equals("星期日");
    }

    private static class OrderItem {
        private String name;
        private int portion;
        private int count;
        private double price;

        public OrderItem(String name, int portion, int count) {
            this(name, portion, count, 0);
        }

        public OrderItem(String name, int portion, int count, double price) {
            this.name = name;
            this.portion = portion;
            this.count = count;
            this.price = price;
        }

        public String getName() {
            return name;
        }

        public int getPortion() {
            return portion;
        }

        public int getCount() {
            return count;
        }

        public double getPrice() {
            return price == 0 ? prices.get(name) * getPortionRate(portion) : price;
        }
    }
}

这个 Java 题目的难度属于中等级别。它涉及到输入输出的处理、字符串的分割和转换、Map 和 List 的使用等基本的编程技巧。

在技术方面,这个题目使用了以下技巧:

1. 使用 Scanner 类来读取用户的输入。
2. 使用 HashMap 来存储菜单的价格信息。
3. 使用 ArrayList 来存储每个桌号的点菜记录。
4. 使用字符串的 split() 方法和 trim() 方法来分割和处理输入的字段。
5. 使用条件语句和循环来判断和处理不同的命令和指令。
6. 使用 Math 类的 round() 方法对总价进行四舍五入。

此外,这个题目也涉及到了一些简单的逻辑判断和数据计算。

总体而言,这个题目可以帮助练习者巩固和应用基本的编程技巧,包括字符串处理、集合的使用和基本的算术运算

第五次题目集:

本次作业比菜单计价系列-3增加的功能:

菜单输入时增加特色菜,特色菜的输入格式:菜品名+英文空格+基础价格+"T"

例如:麻婆豆腐 9 T

菜价的计算方法:

周一至周五 7折, 周末全价。

注意:不同的四舍五入顺序可能会造成误差,请按以下步骤累计一桌菜的菜价:

计算每条记录的菜价:将每份菜的单价按份额进行四舍五入运算后,乘以份数计算多份的价格,然后乘以折扣,再进行四舍五入,得到本条记录的最终支付价格。

最后将所有记录的菜价累加得到整桌菜的价格。

代码如下:

Dish类:

 Menu类:

 Record类:

 Order类:

 Table类:

 Main类:

 类图如下:

 

圈复杂度:

 

 

题目分析:

   此题是菜单类,包含菜品类,菜谱类,点菜记录类和订单类,菜品类主要是对应菜谱上一道菜的信息。菜谱类主要是对应菜谱,包含饭店提供的所有菜的信息。点菜记录类主要是保存订单上的一道菜品记录。订单类主要是保存用户点的所有菜的信息。一开始看到这个题目的时候,我是被吓了一跳的,因为这道题的文字量特别的大,而且在上次的pta上有加了许多别的功能,比如说删除和时间,还有特色菜,有这与普通菜不同的计算价格的方式和打折的方式。在得分上,得分点又被细化,导致不好拿到高分。

踩坑心得:

1,价格的算法出错,注意特色菜的价格算法以及打折的时间。

2,同一桌菜名、份额相同的点菜记录要合并成一条进行计算,否则可能会出现四舍五入的误差。

3,超出范围的返回值错误,导致返回date。

 

第六次题目集:

 

本次课题相比菜单计价系列-3新增要求如下:

1、菜单输入时增加特色菜,特色菜的输入格式:菜品名+英文空格+口味类型+英文空格+基础价格+"T"

菜价的计算方法:

周一至周五 7折, 周末全价。

特色菜的口味类型:川菜、晋菜、浙菜

川菜增加辣度值:辣度0-5级;对应辣度水平为:不辣、微辣、稍辣、辣、很辣、爆辣;

晋菜增加酸度值,酸度0-4级;对应酸度水平为:不酸、微酸、稍酸、酸、很酸;

浙菜增加甜度值,甜度0-3级;对应酸度水平为:不甜、微甜、稍甜、甜;    

输出一桌的信息时,按辣、酸、甜度的顺序依次输出本桌菜各种口味的口味度水平,如果没有某个类型的菜,对应的口味(辣/酸/甜)度不输出,只输出已点的菜的口味度。口味度水平由口味度平均值确定,口味度平均值只综合对应口味菜系的菜计算,不做所有菜的平均。比如,某桌菜点了3份川菜,辣度分别是1、3、5;还有4份晋菜,酸度分别是,1、1、2、2,辣度平均值为3、酸度平均值四舍五入为2,甜度没有,不输出。

一桌信息的输出格式:table+英文空格+桌号+:+英文空格+当前桌的原始总价+英文空格+当前桌的计算折扣后总价+英文空格+"川菜"+数量+辣度+英文空格+"晋菜"+数量+酸度+英文空格+"浙菜"+数量+甜度。

 

2、考虑客户订多桌菜的情况,输入时桌号时,增加用户的信息:

格式:table+英文空格+桌号+英文空格+":"+英文空格+客户姓名+英文空格+手机号+日期(格式:YYYY/MM/DD)+英文空格+ 时间(24小时制格式: HH/MM/SS)

输出用户支付金额格式:

用户姓名+英文空格+手机号+英文空格+支付金额

 

代码如下:

Dish类:

Menu类:

people类:

Record类:

Order类:

 table类:

 main类:

 

 

 

 

 

类图如下:

 

 

圈复杂度: 

 

 

 

题目分析:

       此题是菜单类,包含菜品类,菜谱类,点菜记录类和订单类,菜品类主要是对应菜谱上一道菜的信息。菜谱类主要是对应菜谱,包含饭店提供的所有菜的信息。点菜记录类主要是保存订单上的一道菜品记录,订单类主要是保存用户点的所有菜的信息。这道题对比上次的pta,加入了手机号和排序,加入了口味值,加入了川菜,晋菜,浙菜。代码需要传参的地方更多,很容易传参错误导致输出错误,代码不能得分,在得分上,得分点又被细化,导致不好拿到高分。

踩坑心得:

1,数据类型转换错误,string类和int类转换和输出问题。

2,代码需要传参的地方更多,很容易传参错误导致输出错误。

3,不同的四舍五入顺序可能会造成误差。

4,本题要考虑代点菜的情况,当前桌点的菜要加上被其他桌代点的菜综合计算口味度平均值。

5,输出结果时,同一个客户的所有table金额一定要累加。

6,辣度值超标会返回date。

 

期中考试题目集:

 

第一题:

创建一个圆形类(Circle),私有属性为圆的半径,从控制台输入圆的半径,输出圆的面积

输入格式:

输入圆的半径,取值范围为(0,+∞),输入数据非法,则程序输出Wrong Format,注意:只考虑从控制台输入数值的情况

输出格式:

输出圆的面积(保留两位小数,可以使用String.format(“%.2f”,输出数值)控制精度)

代码如下:

 

 

第二题:

设计一个矩形类,其属性由矩形左上角坐标点(x1,y1)及右下角坐标点(x2,y2)组成,其中,坐标点属性包括该坐标点的X轴及Y轴的坐标值(实型数),求得该矩形的面积。类设计如下图:


image.png

输入格式:

分别输入两个坐标点的坐标值x1,y1,x2,y2。

输出格式:

输出该矩形的面积值(保留两位小数)。

代码如下:

 

第三题:

 

将测验1与测验2的类设计进行合并设计,抽象出Shape父类(抽象类),Circle及Rectangle作为子类,类图如下所示:


image.png

代码如下:

踩坑心得:实际上自己刚遇到题目的时候并没有好好思考怎么去构造代码,而是一看到题目就写,导致总是频频报错,并且也不能跟后面的继承联系上。如果自己在看到题目后能够多加思考再去动笔,可能结果会更不一样。

总结: 在考试中我并没有写出第三题,自己不太会写是一个原因,不够熟练也是一个原因,如果前两题花的时间能够更少一些,也许自己就能够拥有更多的时间去思考第三题和尝试第三题。考试结束后也是经过一定的思考最后把这道题写了出来,所以平常的练习特别重要

 

 

三.改进建议:

1,pta部分题目运行时间超时,要优化代码的算法,很多时候不是你的方法不行,而是有优化的地方没有优化,导致程序运行的时间加长导致超时,现在争取把每个小步骤都优化,以后的大作业程序才能不断的节省时间。

2,pta部分题目非零返回,自己的代码有问题才会导致的,要检查自己的程序逻辑。

3,对继承的方法使用不熟练,对传参的方法也不太熟练,会用但是容易出错,要多使用,防止以后出错。

4,对类的设计要更细节和具体,每个类包含的属性和方法,以及不同类之间的关系。

 

四.总结:

       这些题目总体来说难度大,题目量虽然也不多,但是有些题目还是需要静下心来思考才能做好。期中考试的难度不算很高,前三题还是比较好作对的,第四题的接口我还没有掌握,没能拿下分。通过这数次的PTA作业,我也基本能够掌握java语言中类的作用。这段时间的作业,也让我发现了自己最大的问题,那就是思维比较固化,写的很多程序的思路大多都是按部就班的那种,所以我的思维能力还是很需要培养的。这几次的作业,也基本帮助我们搭建了一个最基本的java语言的框架,让我学会了java的基本语法和类的分类,掌握了面向对象的语言的基本思路,学会了部分菜单的设计,学会了类的调用和部分函数,学会了传参和继承。虽然我还有很多不足和错误,java的语法不够熟练,对类的概念没有充分的掌握,传参也容易出错。希望老师可以更多的讲一下部分有用的java方法,毕竟自己查资料学习的不够系统,通过老师的讲解可以更加深入,系统的学习。