(1)前言
-
知识点
- 类和对象:
类(class)和对象(object)是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型。
它们的关系是,对象是类的实例,类是对象的模板。对象是通过new classname产生的,用来调用类的方法;类的构造方法 。
- 对象交互:
当一个对象里有多个对象的时候,那些对象之间是如何交互的,对象和对象之间的联系是如何建立的,对象如何和其他对象交流。
- 继承与多态:
继承:就是保持已有类的特性而构造新类的过程。继承后,子类能够利用父类中定义的变量和方法,就像它们属于子类本身一样。
多态:(1)一个类继承自某个父类时,对父类中的方法进行改写。
(2)重载是两个方法的名称相同,但参数不同,重载与多态没有关系。
(3)抽象类。
(4)接口(interface)
- 对象容器:
Java具有丰富的容器,Java的容器具有丰富的功能和良好的性能。熟悉并能充分有效地利用好容器,是现代程序设计的基本能力。
- 设计原则:
1、单一职责原则
2、里氏替换原则
3、依赖倒置原则
4、接口隔离原则
5、迪米特法则(最少知道原则)
6、开闭原则
- 抽象:
Java语言中,用abstract 关键字来修饰一个类时,这个类叫作抽象类。抽象类是它的所有子类的公共属性的集合,是包含一个或多
个抽象方法的类。 抽象类可以看作是对类的进一步抽象。在面向对象领域,抽象类主要用来进行类型隐藏。
- 题目数量
- 题目集8:7-1 电信计费系列1-座机计费
- 题目集9:7-1 电信计费系列2-手机+座机计费
- 题目集9:7-1 电信计费系列3-短信计费
- 题目难度
- Medium:
- 题目集9:7-1 电信计费系列3-短信计费
- Hard:
- 题目集8:7-1 电信计费系列1-座机计费
- 题目集9:7-1 电信计费系列2-手机+座机计费
**********************************************************************************************************************************************************************************************************************************************************
**********************************************************************************************************************************************************************************************************************************************************
(2)设计与分析
- 题目集8:7-1 电信计费系列1-座机计费
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
1、针对市内座机用户采用的计费方式(与电信计费系列1内容相同):
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
假设本市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
2、针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
注:被叫电话属于市内、省内还是国内由被叫电话的接听地点区号决定,比如以下案例中,南昌市手机用户13307912264在区号为020的广州接听了电话,主叫号码应被计算为拨打了一个省外长途,同时,手机用户13307912264也要被计算省外接听漫游费:
u-13307912264 1
t-079186330022 13307912264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
输入:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,含手机和座机用户
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题在电信计费系列1基础上增加类型1-手机实时计费。
手机设置0或者座机设置成1,此种错误可不做判断。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
输入格式增加手机接打电话以及收发短信的格式,手机接打电话的信息除了号码之外需要额外记录拨打/接听的地点的区号,比如:
座机打手机:
t-主叫号码 接听号码 接听地点区号 起始时间 结束时间
t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
手机互打:
t-主叫号码 拨号地点 接听号码 接听地点区号 起始时间 结束时间
t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
建议类图:
参见图1、2、3:

图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。

图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。

图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
1,类图:

2,分析:万事开头难,所以毫无疑问对于一个新的迭代类型的题目而言,最开始的设计分析类与类之间的联系和构架是至关重要的,所以我们对这个题目进行尽量全面的考虑。我们要先设计类,我们首先要思考我们需要什么。对于我们而言,我们会需要CallRecord用于储存时间通话记录从而获取时间,LandlinePhoneCharging可以作为一个总和计算,将所有类型的通话方式都放入该类进行计算并且得到结果,LandPhoneInCityRule计算座机在城市里面的话费,LandPhoneInlandRule计算座机在省内里面的话费,LandPhoneInProvinceRule是对于省外的计算座机的话费,我们也就是利用这三个类来放入LandPhoneInCityRule进行计算得到我们所最后需要的结果。User用于储存用户的,UserRecords储存各种通话或者手机通话的所有信息,方便后续提取信息。就此我们对这道题目的剖析就已经结束了,而我们也已经有了大概的框架了,利用这些框架去创建一些你所需要的方法,达到题目的要求即可。
3.源码:
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.Date; public class Main { public static void main(String[] args) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Scanner in = new Scanner(System.in); TreeMap<String,User> users = new TreeMap<>(); String s = in.nextLine(); String check = "u-0791([0-9]{7,8})\\s0"; while( !s.equals("end")){ String check1 = "t-0791([0-9]{7,8})\\s([0-9]{10,12})\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])"; String check2 = "0791([0-9]{7,8})"; if(s.matches(check)) { String []s1 = s.split("-| "); users.put(s1[1], new User(new UserRecords(), 100, new LandlinePhoneCharging())); } else if (s.matches(check1)) { String []s1 = s.split("-| "); for (Map.Entry<String, User> entry : users.entrySet()) { String c1 = s1[3] + ' ' + s1[4]; String c2 = s1[5] + ' ' + s1[6]; try { Date date1 = dateFormat.parse(c1); Date date2 = dateFormat.parse(c2); if (s1[1].equals(entry.getKey())) { CallRecord callRecord = new CallRecord(date1, date2); if (s1[2].charAt(0) == '0' && s1[2].charAt(1) == '7' && s1[2].charAt(2) == '9' && s1[2].charAt(3) == '1') { entry.getValue().userRecords.callingInCityRecords.add(callRecord); } else if ((s1[2].charAt(0) == '0' && s1[2].charAt(1) == '7' && ((s1[2].charAt(2) == '9' && s1[2].charAt(3) >= '0' && s1[2].charAt(3) <= '9') || (s1[2].charAt(2) == '0' && s1[2].charAt(3) == '1')))) { entry.getValue().userRecords.callingInProvinceRecords.add(callRecord); } else { entry.getValue().userRecords.callingInLandRecords.add(callRecord); } } } catch (ParseException e) { e.printStackTrace(); } } } s = in.nextLine(); } for (Map.Entry<String, User> entry : users.entrySet()) { System.out.print(entry.getKey()+" "); System.out.printf("%.1f %.1f\n",(new LandlinePhoneCharging().calCost(entry.getValue().userRecords)-20),(100-new LandlinePhoneCharging().calCost(entry.getValue().userRecords))); } } } abstract class CallChargeRule extends ChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ return 0; } } class CallRecord { private Date startTime; private Date endTime; private String callingAddressAreaCode; private String answerAddressAreaCode; public CallRecord(Date startTime, Date endTime) { this.startTime = startTime; this.endTime = endTime; } public long Day(){ long stateTimeLong = getStartTime().getTime(); long endTimeLong = getEndTime().getTime(); long second = (endTimeLong-stateTimeLong)/1000; return second; } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } } abstract class ChargeMode { ArrayList <ChargeRule> arrayList = new ArrayList<>(); public ChargeMode() { this.arrayList = arrayList; } public ArrayList<ChargeRule> getArrayList() { return arrayList; } public void setArrayList(ArrayList<ChargeRule> arrayList) { this.arrayList = arrayList; } public double calCost (UserRecords userRecords){ return 0; } public double getMonthlyRent (){ return 20; } } class ChargeRule { } class Data { int year,month,day,hour,min,sec; public Data(int year, int month, int day, int hour, int min, int sec) { this.year = year; this.month = month; this.day = day; this.hour = hour; this.min = min; this.sec = sec; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } public int getHour() { return hour; } public void setHour(int hour) { this.hour = hour; } public int getMin() { return min; } public void setMin(int min) { this.min = min; } public int getSec() { return sec; } public void setSec(int sec) { this.sec = sec; } public boolean check(String []s1){ SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy.MM.dd"); SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("HH:mm:ss"); return simpleDateFormat1.equals(s1[3])&&simpleDateFormat1.equals(s1[5])&&simpleDateFormat2.equals(s1[4])&&simpleDateFormat2.equals(s1[6]); } } class LandlinePhoneCharging extends ChargeMode{ double monthlyRent = 20; public LandlinePhoneCharging() { super(); } public double calCost (UserRecords userRecords){ LandPhoneInlandRule landPhoneInlandRule = new LandPhoneInlandRule(); LandPhoneInCityRule landPhoneInCityRule = new LandPhoneInCityRule(); LandPhoneInProvinceRule landPhoneInProvinceRule = new LandPhoneInProvinceRule(); return landPhoneInCityRule.calCost(userRecords.callingInCityRecords)+landPhoneInProvinceRule.calCost(userRecords.callingInProvinceRecords) +landPhoneInlandRule.calCost(userRecords.callingInLandRecords)+getMonthlyRent(); } public double getMonthlyRent (){ return monthlyRent; } } class LandPhoneInCityRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.1; } } class LandPhoneInlandRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.6; } } class LandPhoneInProvinceRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } } class User { UserRecords userRecords = new UserRecords(); private double balance = 100; LandlinePhoneCharging landlinePhoneCharging; private String number; public User(UserRecords userRecords, double balance, LandlinePhoneCharging landlinePhoneCharging) { this.userRecords = userRecords; this.balance = balance; this.landlinePhoneCharging = landlinePhoneCharging; } public User(UserRecords userRecords) { } public double calBalance(){ return 0; } public UserRecords getUserRecords() { return userRecords; } public void setUserRecords(UserRecords userRecords) { this.userRecords = userRecords; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public LandlinePhoneCharging getLandlinePhoneCharging() { return landlinePhoneCharging; } public void setLandlinePhoneCharging(LandlinePhoneCharging landlinePhoneCharging) { this.landlinePhoneCharging = landlinePhoneCharging; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } } class UserRecords { ArrayList <CallRecord> callingInCityRecords = new ArrayList<>(); ArrayList <CallRecord> callingInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> callingInLandRecords = new ArrayList<>(); ArrayList <CallRecord> answerInCityRecords = new ArrayList<>(); ArrayList <CallRecord> answerInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> answerInLandRecords = new ArrayList<>(); ArrayList <MessageRecord> sendMessageRecords = new ArrayList<>(); ArrayList <MessageRecord> receiveMessageRecords = new ArrayList<>(); public void addCallingInCityRecords (CallRecord callRecord){ callingInCityRecords.add(callRecord); } public void addCallingInProvinceRecords(CallRecord callRecord){ callingInProvinceRecords.add(callRecord); } public void addCallingInLandRecords(CallRecord callRecord){ callingInLandRecords.add(callRecord); } public void addAnswerInCityRecords(CallRecord callRecord){ answerInCityRecords.add(callRecord); } public void addAnswerInProvinceRecords(CallRecord callRecord){ answerInProvinceRecords.add(callRecord); } public void addSendMessageRecords(MessageRecord messageRecord){ sendMessageRecords.add(messageRecord); } public void addReceiveMessageRecords(MessageRecord messageRecord){ receiveMessageRecords.add(messageRecord); } public void addAnswerInLandRecords(CallRecord callRecord){ answerInLandRecords.add(callRecord); } public ArrayList<CallRecord> getCallingInCityRecords() { return callingInCityRecords; } public ArrayList<CallRecord> getCallingInProvinceRecords() { return callingInProvinceRecords; } public ArrayList<CallRecord> getCallingInLandRecords() { return callingInLandRecords; } public ArrayList<CallRecord> getAnswerInCityRecords() { return answerInCityRecords; } public ArrayList<CallRecord> getAnswerInProvinceRecords() { return answerInProvinceRecords; } public ArrayList<CallRecord> getAnswerInLandRecords() { return answerInLandRecords; } public ArrayList<MessageRecord> getSendMessageRecords() { return sendMessageRecords; } public ArrayList<MessageRecord> getReceiveMessageRecords() { return receiveMessageRecords; } } class MessageRecord { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
3.我的心得:对于这种题目的要义就在于捋清楚类与类之间的联系,从而创建你所需要的类,并且在其中填写你所需要的方法完成题目功能,其次还有一个非常非常重要的点,就是正则表达式,如果说捋清楚类与类之间的联系是你做这道题目的下限的话,那么一个完美的正则表达式会决定你的上限,有没有把所有的情况全部考虑清楚,这是非常重要的,我建议要认认真真把题目多读几遍,你一定会发现每一次读你都会有新的收获,会发现自己的新的盲点,这样就可以更加完善你自己的正则表达式,从而去追求满分的结果。
- 7-1 电信计费系列2-手机+座机计费
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
1、针对市内座机用户采用的计费方式(与电信计费系列1内容相同):
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
假设本市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
2、针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
注:被叫电话属于市内、省内还是国内由被叫电话的接听地点区号决定,比如以下案例中,南昌市手机用户13307912264在区号为020的广州接听了电话,主叫号码应被计算为拨打了一个省外长途,同时,手机用户13307912264也要被计算省外接听漫游费:
u-13307912264 1
t-079186330022 13307912264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
输入:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,含手机和座机用户
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题在电信计费系列1基础上增加类型1-手机实时计费。
手机设置0或者座机设置成1,此种错误可不做判断。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
输入格式增加手机接打电话以及收发短信的格式,手机接打电话的信息除了号码之外需要额外记录拨打/接听的地点的区号,比如:
座机打手机:
t-主叫号码 接听号码 接听地点区号 起始时间 结束时间
t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
手机互打:
t-主叫号码 拨号地点 接听号码 接听地点区号 起始时间 结束时间
t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
建议类图:
参见图1、2、3:

图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。

图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。

图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
1,类图:


2,源码:
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.Date; public class Main { public static void main(String[] args) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Scanner in = new Scanner(System.in); TreeMap<String,User> users = new TreeMap<>(); String s = in.nextLine(); String check = "u-0791([0-9]{7,8})\\s0"; while( !s.equals("end")){ String check1 = "t-0791([0-9]{7,8})\\s([0-9]{10,12})\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])"; String check3 = "t-0791([0-9]{7,8})\\s1([0-9]{10})\\s\\d{3,4}\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])"; String check4 = "t-1([0-9]{10})\\s\\d{3,4}\\s([0-9]{10,12})\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])"; String check7 = "t-1([0-9]{10})\\s\\d{3,4}\\s1([0-9]{10})\\s\\d{3,4}\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])\\s\\d{4}\\.([1-9]|1[012])\\.([1-9]|([1-2][0-9])|[3][0,1])\\s((0[0-9])|(1[0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])"; String check2 = "u-1([0-9]{10})\\s1"; String check5 = "07((9[0-9])|(01))"; String check8 = "0791([0-9]{7,8})"; if(s.matches(check)||s.matches(check2)) { String []s1 = s.split("-| "); users.put(s1[1], new User(new UserRecords(), 100, new LandlinePhoneCharging())); } else if (s.matches(check1)||s.matches(check3)||s.matches(check4)||s.matches(check7)) { String []s1 = s.split("-| "); if(s1.length==7) { for (Map.Entry<String, User> entry : users.entrySet()) { String c1 = s1[3] + ' ' + s1[4]; String c2 = s1[5] + ' ' + s1[6]; try { Date date1 = dateFormat.parse(c1); Date date2 = dateFormat.parse(c2); if (s1[1].equals(entry.getKey())) { CallRecord callRecord = new CallRecord(date1, date2); if (s1[2].charAt(0) == '0' && s1[2].charAt(1) == '7' && s1[2].charAt(2) == '9' && s1[2].charAt(3) == '1') { entry.getValue().userRecords.callingInCityRecords.add(callRecord); } else if ((s1[2].charAt(0) == '0' && s1[2].charAt(1) == '7' && ((s1[2].charAt(2) == '9' && s1[2].charAt(3) >= '0' && s1[2].charAt(3) <= '9') || (s1[2].charAt(2) == '0' && s1[2].charAt(3) == '1')))) { entry.getValue().userRecords.callingInProvinceRecords.add(callRecord); } else { entry.getValue().userRecords.callingInLandRecords.add(callRecord); } } } catch (ParseException e) { e.printStackTrace(); } } }else if(s1.length == 8&&s1[3].length()<=4){ String c1 = s1[4] + ' ' + s1[5]; String c2 = s1[6] + ' ' + s1[7]; try { Date date11 = dateFormat.parse(c1); Date date22 = dateFormat.parse(c2); for (Map.Entry<String, User> entry1 : users.entrySet()) { if (s1[2].equals(entry1.getKey())) { CallRecord callRecord = new CallRecord(date11, date22); if (!s1[3].matches(check5)) { entry1.getValue().userRecords.answerInLandRecords.add(callRecord); } } } } catch (ParseException e) { e.printStackTrace(); } for (Map.Entry<String, User> entry : users.entrySet()) { try { Date date1 = dateFormat.parse(c1); Date date2 = dateFormat.parse(c2); if (s1[1].equals(entry.getKey())) { CallRecord callRecord = new CallRecord(date1, date2); if (s1[3].equals("0791")) { entry.getValue().userRecords.callingInCityRecords.add(callRecord); } else if (s1[3].matches(check5)) { entry.getValue().userRecords.callingInProvinceRecords.add(callRecord); } else { entry.getValue().userRecords.callingInLandRecords.add(callRecord); } } } catch (ParseException e) { e.printStackTrace(); } } }else if(s1.length ==9){ String c1 = s1[5] + ' ' + s1[6]; String c2 = s1[7] + ' ' + s1[8]; try { Date date11 = dateFormat.parse(c1); Date date22 = dateFormat.parse(c2); for (Map.Entry<String, User> entry1 : users.entrySet()) { if (s1[3].equals(entry1.getKey())) { CallRecord callRecord = new CallRecord(date11, date22); if (!s1[4].matches(check5)) { entry1.getValue().userRecords.answerInLandRecords.add(callRecord); } } } } catch (ParseException e) { e.printStackTrace(); } for (Map.Entry<String, User> entry : users.entrySet()) { try { Date date1 = dateFormat.parse(c1); Date date2 = dateFormat.parse(c2); if (s1[1].equals(entry.getKey())) { CallRecord callRecord = new CallRecord(date1, date2); if (s1[2].equals("0791")) { if (s1[4].equals("0791")) { entry.getValue().userRecords.callingInCityRecords.add(callRecord); } else if (s1[4].matches(check5)) { entry.getValue().userRecords.callingInProvinceRecords.add(callRecord); } else { entry.getValue().userRecords.callingInLandRecords.add(callRecord); } }else if(s1[2].matches(check5)){ entry.getValue().userRecords.manYouCallingInProvinceRecords.add(callRecord); }else{ entry.getValue().userRecords.manYouCallingInLandRecords.add(callRecord); } }} catch (ParseException e) { e.printStackTrace(); } } }else{ String c1 = s1[4] + ' ' + s1[5]; String c2 = s1[6] + ' ' + s1[7]; for (Map.Entry<String, User> entry : users.entrySet()) { try { Date date1 = dateFormat.parse(c1); Date date2 = dateFormat.parse(c2); if (s1[1].equals(entry.getKey())) { CallRecord callRecord = new CallRecord(date1, date2); if(s1[2].equals("0791")&&s1[3].matches(check8)){ entry.getValue().userRecords.callingInCityRecords.add(callRecord); }else if(s1[2].equals("0791")&&s1[3].matches(check5)){ entry.getValue().userRecords.callingInProvinceRecords.add(callRecord); }else if(s1[2].equals("0791")){ entry.getValue().userRecords.callingInLandRecords.add(callRecord); } else if(s1[2].matches(check5)){ entry.getValue().userRecords.manYouCallingInProvinceRecords.add(callRecord); }else{ entry.getValue().userRecords.manYouCallingInLandRecords.add(callRecord); } }} catch (ParseException e) { e.printStackTrace(); } } } } s = in.nextLine(); } for (Map.Entry<String, User> entry : users.entrySet()) { if (entry.getKey().charAt(0) == '0') { System.out.print(entry.getKey() + " "); System.out.printf("%.1f %.1f\n", (new LandlinePhoneCharging().calCost(entry.getValue().userRecords) - 20), (100 - new LandlinePhoneCharging().calCost(entry.getValue().userRecords))); }else{ System.out.print(entry.getKey() + " "); System.out.printf("%.1f %.1f\n",new MobliePhoneCharging().calCost(entry.getValue().userRecords)-15,100-new MobliePhoneCharging().calCost(entry.getValue().userRecords)); } } } } abstract class CallChargeRule extends ChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ return 0; } } class CallRecord { private Date startTime; private Date endTime; private String callingAddressAreaCode; private String answerAddressAreaCode; public CallRecord(Date startTime, Date endTime) { this.startTime = startTime; this.endTime = endTime; } public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { this.startTime = startTime; this.endTime = endTime; this.callingAddressAreaCode = callingAddressAreaCode; this.answerAddressAreaCode = answerAddressAreaCode; } public long Day(){ long stateTimeLong = getStartTime().getTime(); long endTimeLong = getEndTime().getTime(); long second = (endTimeLong-stateTimeLong)/1000; return second; } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } } abstract class ChargeMode { ArrayList <ChargeRule> arrayList = new ArrayList<>(); public ChargeMode() { this.arrayList = arrayList; } public ArrayList<ChargeRule> getArrayList() { return arrayList; } public void setArrayList(ArrayList<ChargeRule> arrayList) { this.arrayList = arrayList; } public double calCost (UserRecords userRecords){ return 0; } public double getMonthlyRent (){ return 20; } } class ChargeRule { } abstract class CommunicationRecord { private String callingNumber; private String answerNumber; public String getCallingNumber() { return callingNumber; } public void setCallingNumber(String callingNumber) { this.callingNumber = callingNumber; } public String getAnswerNumber() { return answerNumber; } public void setAnswerNumber(String answerNumber) { this.answerNumber = answerNumber; } } class LandlinePhoneCharging extends ChargeMode{ double monthlyRent = 20; public LandlinePhoneCharging() { super(); } public double calCost (UserRecords userRecords){ LandPhoneInlandRule landPhoneInlandRule = new LandPhoneInlandRule(); LandPhoneInCityRule landPhoneInCityRule = new LandPhoneInCityRule(); LandPhoneInProvinceRule landPhoneInProvinceRule = new LandPhoneInProvinceRule(); return landPhoneInCityRule.calCost(userRecords.callingInCityRecords)+landPhoneInProvinceRule.calCost(userRecords.callingInProvinceRecords) +landPhoneInlandRule.calCost(userRecords.callingInLandRecords)+getMonthlyRent(); } public double getMonthlyRent (){ return monthlyRent; } } class LandPhoneInCityRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.1; } } class LandPhoneInlandRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.6; } public double phoneCalCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } public double answerInLandCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } public double manYouCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.6; } } class LandPhoneInProvinceRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } public double phoneCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.2; } public double manYouCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } } class MobliePhoneCharging extends ChargeMode{ double monthlyRent = 15; public MobliePhoneCharging() { super(); } public double calCost (UserRecords userRecords){ LandPhoneInlandRule landPhoneInlandRule = new LandPhoneInlandRule(); LandPhoneInCityRule landPhoneInCityRule = new LandPhoneInCityRule(); LandPhoneInProvinceRule landPhoneInProvinceRule = new LandPhoneInProvinceRule(); return landPhoneInCityRule.calCost(userRecords.callingInCityRecords)+landPhoneInProvinceRule.phoneCalCost(userRecords.callingInProvinceRecords) +landPhoneInlandRule.phoneCalCost(userRecords.callingInLandRecords)+landPhoneInlandRule.answerInLandCalCost(userRecords.answerInLandRecords)+ landPhoneInProvinceRule.manYouCalCost(userRecords.manYouCallingInProvinceRecords)+getMonthlyRent()+ landPhoneInlandRule.manYouCalCost(userRecords.manYouCallingInLandRecords); } public double getMonthlyRent (){ return monthlyRent; } } class User { UserRecords userRecords = new UserRecords(); private double balance = 100; LandlinePhoneCharging landlinePhoneCharging; private String number; public User(UserRecords userRecords, double balance, LandlinePhoneCharging landlinePhoneCharging) { this.userRecords = userRecords; this.balance = balance; this.landlinePhoneCharging = landlinePhoneCharging; } public User(UserRecords userRecords) { } public double calBalance(){ return 0; } public UserRecords getUserRecords() { return userRecords; } public void setUserRecords(UserRecords userRecords) { this.userRecords = userRecords; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public LandlinePhoneCharging getLandlinePhoneCharging() { return landlinePhoneCharging; } public void setLandlinePhoneCharging(LandlinePhoneCharging landlinePhoneCharging) { this.landlinePhoneCharging = landlinePhoneCharging; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } } class UserRecords { ArrayList <CallRecord> callingInCityRecords = new ArrayList<>(); ArrayList <CallRecord> callingInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> callingInLandRecords = new ArrayList<>(); ArrayList <CallRecord> manYouCallingInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> manYouCallingInLandRecords = new ArrayList<>(); ArrayList <CallRecord> answerInCityRecords = new ArrayList<>(); ArrayList <CallRecord> answerInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> answerInLandRecords = new ArrayList<>(); ArrayList <MessageRecord> sendMessageRecords = new ArrayList<>(); ArrayList <MessageRecord> receiveMessageRecords = new ArrayList<>(); public void addCallingInCityRecords (CallRecord callRecord){ callingInCityRecords.add(callRecord); } public void addCallingInProvinceRecords(CallRecord callRecord){ callingInProvinceRecords.add(callRecord); } public void addCallingInLandRecords(CallRecord callRecord){ callingInLandRecords.add(callRecord); } public void addAnswerInCityRecords(CallRecord callRecord){ answerInCityRecords.add(callRecord); } public void addAnswerInProvinceRecords(CallRecord callRecord){ answerInProvinceRecords.add(callRecord); } public void addSendMessageRecords(MessageRecord messageRecord){ sendMessageRecords.add(messageRecord); } public void addReceiveMessageRecords(MessageRecord messageRecord){ receiveMessageRecords.add(messageRecord); } public void addAnswerInLandRecords(CallRecord callRecord){ answerInLandRecords.add(callRecord); } public ArrayList<CallRecord> getCallingInCityRecords() { return callingInCityRecords; } public ArrayList<CallRecord> getCallingInProvinceRecords() { return callingInProvinceRecords; } public ArrayList<CallRecord> getCallingInLandRecords() { return callingInLandRecords; } public ArrayList<CallRecord> getAnswerInCityRecords() { return answerInCityRecords; } public ArrayList<CallRecord> getAnswerInProvinceRecords() { return answerInProvinceRecords; } public ArrayList<CallRecord> getAnswerInLandRecords() { return answerInLandRecords; } public ArrayList<MessageRecord> getSendMessageRecords() { return sendMessageRecords; } public ArrayList<MessageRecord> getReceiveMessageRecords() { return receiveMessageRecords; } } class MessageRecord { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
3,分析:第二次迭代中添加了手机操作,此处应该是有好几种设计方法,我在这里我只是单纯说一下我的设计思路。对于增加了手机的一些功能,所以增加了不只是一倍的量,因为手机和座机的互通,手机与手机的互通以及不同情况的收费标准都会对我们的做题产生比较大的影响,所以对于情况的考虑又会显得尤为重要。这里我采用的是依葫芦画瓢,也就是大体上是仿照座机与座机之间的通话从而设计出相对应的手机类,从而利用差不多的方法来进行新添加的功能设计,这里我是添加了MobliePhoneCharging来计算手机的所有计费,同时在所有座机通话的不同区域的计算类里面添加手机对应的不同区域的方法来进行分步计算,达到手机计费的目的,我觉得最重要的还是要考虑清楚情况,不然非常容易造成情况漏写,有大片分数没有拿到。另外一个难点和容易扣分的点就是我们的老朋友——正则表达式,对于不合法的输入测试点是给了相当多的,所以也可以看出来正则表达式的重要性,对于题目含义考虑清楚,不要把一些非法输入漏了,就可以在非法输入这一块拿到满分,基本上就已经成功了一半了。
4,我的心得:对于第二次迭代,我认为这是有一定难度的,但是也因为第一次的作业,所以这次作业的难度也降低了不少。只要仔细分析这次作业的需求分析,就可以比较轻松的完成对程序的编写,在这道题目花费的时间比之前的作业要少很多,我的第一次提交得到了76分,还有两个测试点没过,原因就在于没有考虑座机拨打手机的情况,导致有部分bug,所以一定是需要考虑清楚所有情况。
- 7-1 电信计费系列3-短信计费
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
1、针对市内座机用户采用的计费方式(与电信计费系列1内容相同):
月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
假设本市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。
2、针对手机用户采用实时计费方式:
月租15元,市内省内接电话均免费,市内拨打市内电话0.1元/分钟,市内拨打省内电话0.2元/分钟,市内拨打省外电话0.3元/分钟,省内漫游打电话0.3元/分钟,省外漫游接听0.3元/分钟,省外漫游拨打0.6元/分钟;
注:被叫电话属于市内、省内还是国内由被叫电话的接听地点区号决定,比如以下案例中,南昌市手机用户13307912264在区号为020的广州接听了电话,主叫号码应被计算为拨打了一个省外长途,同时,手机用户13307912264也要被计算省外接听漫游费:
u-13307912264 1
t-079186330022 13307912264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
输入:
输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,含手机和座机用户
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题在电信计费系列1基础上增加类型1-手机实时计费。
手机设置0或者座机设置成1,此种错误可不做判断。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
输入格式增加手机接打电话以及收发短信的格式,手机接打电话的信息除了号码之外需要额外记录拨打/接听的地点的区号,比如:
座机打手机:
t-主叫号码 接听号码 接听地点区号 起始时间 结束时间
t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
手机互打:
t-主叫号码 拨号地点 接听号码 接听地点区号 起始时间 结束时间
t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11
注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
输出:
根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,单位元)。假设每个用户初始余额是100元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
本题只做格式的错误判断,无需做内容上不合理的判断,比如同一个电话两条通讯记录的时间有重合、开户号码非南昌市的号码等,此类情况都当成正确的输入计算。但时间的输入必须符合要求,比如不能输入2022.13.61 28:72:65。
建议类图:
参见图1、2、3:

图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。
ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。
UserRecords是用户记录类,保存用户各种通话、短信的记录,
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。

图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。

图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。
1,类图:

2,分析:对于这次迭代而言其实就已经算是非常简单了,没有什么难度,很大程度上是因为我们在前两次作业已经花费很多时间去分析和构建这次的题目,所以对于这道
题目只是单纯的加入了短信功能,并且只针对于手机与手机,内容较为单一,构造较为简单。只需在原来基础上将短信功能填充进去就OK了。
3,源码:
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.Date; public class Main { public static void main(String[] args) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); Scanner in = new Scanner(System.in); TreeMap<String,User> users = new TreeMap<>(); String s = in.nextLine(); String check = "u-0791([0-9]{7,8})\\s3"; while( !s.equals("end")){ String check2 = "[u][-]1[3-9]\\d{9}[ ][3]"; String messagejudge = "m-1[3-9]\\d{9} 1[3-9]\\d{9} [a-z|0-9| |,|.]++"; if(s.matches(check2)) { String []s1 = s.split("-| "); users.put(s1[1], new User(new UserRecords(), 100, 0)); } if(s.matches(messagejudge)){ for (Map.Entry<String, User> entry : users.entrySet()) { String []s2 = s.split("-| ",4); if (s2[1].equals(entry.getKey())){ String s3 =s2[3]; MessageRecord messageRecord = new MessageRecord(s3.length()); entry.getValue().userRecords.sendMessageRecords.add(messageRecord); } } } s = in.nextLine(); } for (Map.Entry<String, User> entry : users.entrySet()) { System.out.print(entry.getKey() + " "); System.out.printf("%.1f %.1f\n",100-new SendMessageRule().calCost(entry.getValue().userRecords.sendMessageRecords),new SendMessageRule().calCost(entry.getValue().userRecords.sendMessageRecords)); } } } class SendMessageRule extends MessageChargeRule { public double calCost(ArrayList<MessageRecord> callRecords) { double sum = 0; int num = 0; for (int i = 0; i < callRecords.size(); i++) { if (callRecords.get(i).getLength() % 10 == 0) { num += callRecords.get(i).getLength() / 10; } else { num+=callRecords.get(i).getLength()/10+1; } } if(num<=3){ return 100-num*0.1; }else if(num<=5){ return 100-3*0.1-(num-3)*0.2; }else{ return 100-3*0.1-2*0.2-0.3*(num-5); } } } class MessageRecord { private int length; public MessageRecord(int length) { this.length = length; } public int getLength() { return length; } public void setLength(int length) { this.length = length; } } class MessageChargeRule extends ChargeRule{ } class User { UserRecords userRecords = new UserRecords(); private double balance = 100; LandlinePhoneCharging landlinePhoneCharging; private String number; private int num; public User(UserRecords userRecords, double balance, LandlinePhoneCharging landlinePhoneCharging) { this.userRecords = userRecords; this.balance = balance; this.landlinePhoneCharging = landlinePhoneCharging; } public User(UserRecords userRecords,double balance,int num) { this.userRecords = userRecords; this.balance = balance; this.num = num; } public double calBalance(){ return 0; } public UserRecords getUserRecords() { return userRecords; } public void setUserRecords(UserRecords userRecords) { this.userRecords = userRecords; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public LandlinePhoneCharging getLandlinePhoneCharging() { return landlinePhoneCharging; } public void setLandlinePhoneCharging(LandlinePhoneCharging landlinePhoneCharging) { this.landlinePhoneCharging = landlinePhoneCharging; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } } class UserRecords { ArrayList <CallRecord> callingInCityRecords = new ArrayList<>(); ArrayList <CallRecord> callingInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> callingInLandRecords = new ArrayList<>(); ArrayList <CallRecord> manYouCallingInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> manYouCallingInLandRecords = new ArrayList<>(); ArrayList <CallRecord> answerInCityRecords = new ArrayList<>(); ArrayList <CallRecord> answerInProvinceRecords = new ArrayList<>(); ArrayList <CallRecord> answerInLandRecords = new ArrayList<>(); ArrayList <MessageRecord> sendMessageRecords = new ArrayList<>(); ArrayList <MessageRecord> receiveMessageRecords = new ArrayList<>(); public void addCallingInCityRecords (CallRecord callRecord){ callingInCityRecords.add(callRecord); } public void addCallingInProvinceRecords(CallRecord callRecord){ callingInProvinceRecords.add(callRecord); } public void addCallingInLandRecords(CallRecord callRecord){ callingInLandRecords.add(callRecord); } public void addAnswerInCityRecords(CallRecord callRecord){ answerInCityRecords.add(callRecord); } public void addAnswerInProvinceRecords(CallRecord callRecord){ answerInProvinceRecords.add(callRecord); } public void addSendMessageRecords(MessageRecord messageRecord){ sendMessageRecords.add(messageRecord); } public void addReceiveMessageRecords(MessageRecord messageRecord){ receiveMessageRecords.add(messageRecord); } public void addAnswerInLandRecords(CallRecord callRecord){ answerInLandRecords.add(callRecord); } public ArrayList<CallRecord> getCallingInCityRecords() { return callingInCityRecords; } public ArrayList<CallRecord> getCallingInProvinceRecords() { return callingInProvinceRecords; } public ArrayList<CallRecord> getCallingInLandRecords() { return callingInLandRecords; } public ArrayList<CallRecord> getAnswerInCityRecords() { return answerInCityRecords; } public ArrayList<CallRecord> getAnswerInProvinceRecords() { return answerInProvinceRecords; } public ArrayList<CallRecord> getAnswerInLandRecords() { return answerInLandRecords; } public ArrayList<MessageRecord> getSendMessageRecords() { return sendMessageRecords; } public ArrayList<MessageRecord> getReceiveMessageRecords() { return receiveMessageRecords; } } abstract class CallChargeRule extends ChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ return 0; } } class CallRecord { private Date startTime; private Date endTime; private String callingAddressAreaCode; private String answerAddressAreaCode; public CallRecord(Date startTime, Date endTime) { this.startTime = startTime; this.endTime = endTime; } public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) { this.startTime = startTime; this.endTime = endTime; this.callingAddressAreaCode = callingAddressAreaCode; this.answerAddressAreaCode = answerAddressAreaCode; } public long Day(){ long stateTimeLong = getStartTime().getTime(); long endTimeLong = getEndTime().getTime(); long second = (endTimeLong-stateTimeLong)/1000; return second; } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getCallingAddressAreaCode() { return callingAddressAreaCode; } public void setCallingAddressAreaCode(String callingAddressAreaCode) { this.callingAddressAreaCode = callingAddressAreaCode; } public String getAnswerAddressAreaCode() { return answerAddressAreaCode; } public void setAnswerAddressAreaCode(String answerAddressAreaCode) { this.answerAddressAreaCode = answerAddressAreaCode; } } abstract class ChargeMode { ArrayList <ChargeRule> arrayList = new ArrayList<>(); public ChargeMode() { this.arrayList = arrayList; } public ArrayList<ChargeRule> getArrayList() { return arrayList; } public void setArrayList(ArrayList<ChargeRule> arrayList) { this.arrayList = arrayList; } public double calCost (UserRecords userRecords){ return 0; } public double getMonthlyRent (){ return 20; } } class ChargeRule { } abstract class CommunicationRecord { private String callingNumber; private String answerNumber; public String getCallingNumber() { return callingNumber; } public void setCallingNumber(String callingNumber) { this.callingNumber = callingNumber; } public String getAnswerNumber() { return answerNumber; } public void setAnswerNumber(String answerNumber) { this.answerNumber = answerNumber; } } class LandlinePhoneCharging extends ChargeMode{ double monthlyRent = 20; public LandlinePhoneCharging() { super(); } public double calCost (UserRecords userRecords){ LandPhoneInlandRule landPhoneInlandRule = new LandPhoneInlandRule(); LandPhoneInCityRule landPhoneInCityRule = new LandPhoneInCityRule(); LandPhoneInProvinceRule landPhoneInProvinceRule = new LandPhoneInProvinceRule(); return landPhoneInCityRule.calCost(userRecords.callingInCityRecords)+landPhoneInProvinceRule.calCost(userRecords.callingInProvinceRecords) +landPhoneInlandRule.calCost(userRecords.callingInLandRecords)+getMonthlyRent(); } public double getMonthlyRent (){ return monthlyRent; } } class LandPhoneInCityRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.1; } } class LandPhoneInlandRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.6; } public double phoneCalCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } public double answerInLandCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } public double manYouCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.6; } } class LandPhoneInProvinceRule extends CallChargeRule{ public double calCost (ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } public double phoneCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.2; } public double manYouCalCost(ArrayList<CallRecord> callRecords){ double sum = 0; for (CallRecord callRecord : callRecords) { sum+=Math.ceil(callRecord.Day()/60.0); } return sum*0.3; } } class MobliePhoneCharging extends ChargeMode{ double monthlyRent = 15; public MobliePhoneCharging() { super(); } public double calCost (UserRecords userRecords){ LandPhoneInlandRule landPhoneInlandRule = new LandPhoneInlandRule(); LandPhoneInCityRule landPhoneInCityRule = new LandPhoneInCityRule(); LandPhoneInProvinceRule landPhoneInProvinceRule = new LandPhoneInProvinceRule(); return landPhoneInCityRule.calCost(userRecords.callingInCityRecords)+landPhoneInProvinceRule.phoneCalCost(userRecords.callingInProvinceRecords) +landPhoneInlandRule.phoneCalCost(userRecords.callingInLandRecords)+landPhoneInlandRule.answerInLandCalCost(userRecords.answerInLandRecords)+ landPhoneInProvinceRule.manYouCalCost(userRecords.manYouCallingInProvinceRecords)+getMonthlyRent()+ landPhoneInlandRule.manYouCalCost(userRecords.manYouCallingInLandRecords); } public double getMonthlyRent (){ return monthlyRent; } }
3,我的心得:这次相较于之前两次基本上可以说是小巫见大巫了,这里大家也基本上都是满分,我就不再赘述了。
(3)踩坑心得
作为踩坑无数的老废物,可以说是经验丰富,下面我就浅谈一下我的废物行为
- 正则表达式
心得:正则表达式,正则表达式,正则表达式非常非常非常重要,重要的事情说三遍,下面我也针对于这个来简单说一下我的一些方法。
1,确定输入电话号码的位数。
2,确定开头标志符号是否正确。
3,确定输入的电话号码是合法的电话(包含座机)。
4,确定输入日期和时间的正确。
5,确定输入区域的准确性。
如果确定了以上的正则表达式的正确性,那么在这次题目中,就不会出现什么太大的问题。
对于正则表达式的训练我觉得只要经常去做题,并且多去正则表达式的测试器里面去测试,就可以达到训练效果。



- 情况分析
心得:对于这种类型的题目来说,我们需要认真分析,这也就意味着是需要将情况进行分析处理情况。
1,题目的大概确定下来。
2,将大致的各个方向在纸上画下来。
3,将每一种情况中与另一种情况的分析或者其本身具有的各种情况进行分析。
4,进行各类情况进行代码实现。
在这次作业中我就是因为遗漏了情况,从而花费很多时间去查找自己的问题,所以以后一定要养好认真读题,认真分析的好习惯,不要上来敲代码,
这样会对后来的代码实现造成遗漏,造成非常不好的结果。
- 储存选择
心得:使用TreeMap来代替ArrayList,优点体现
1、TreeMap是一个有序的key-value集合,它内部是通过红-黑树实现的,它支持序列化 。
2、TreeMap的存储结构是按照红-黑树存储的,每个key-value对也存储在一个Entry里,只不过这个Entry和前面HashMap或者HashTable中的Entry不同,TreeMap的Entry 其实是红-黑树的一个节点。
(4)改进建议
- 正则表达式:对于正则表达式的简化,我之前使用的正则表达式是非常复杂的,采用了最笨的方法,对于字符串一个一个进行判断,这种方法太过于笨拙,所以这种方法是需要进行改进的。

- 思维流程:对于这次题目的前期准备工作还是不够完善,以至于在第二次作业因为漏考虑一种情况耽误太久时间,下次应该将情况全部列出来,而不是在脑子里面过一遍。

- 代码的可扩展性:在main函数中我使用了太多代码去直接填充各种情况,其实这样是非常不好的习惯,应该将各种情况进行分类,然后再进行填充。
(5)总结
-
收获
- 对java的类和对象了解更加深刻,并且已经开始学着去使用它。
- 编码的优化程度大大提高,程序的可读性更好了。
-
不足
一.对java的熟练程度有待提高,还是过于依赖之前C语言的固有思维。
二.对题目的细节考虑不清,非常容易犯一些细节错误,造成测试点的错误。
-
通过本阶段三次题目集的训练对教师、课程、作业、实验、课上及课下组织方式等方面提出的改进建议及意见
- 老师的教学速度是可以接受的,但是试题难度跳跃性过大,学生需要花费非常多时间去学习掌握。
- 希望老师可以对pta的题目进行分析和讲解。

浙公网安备 33010602011771号