一、前言

这是这学期最后一次总结,这三次的pta大作业也是最后一次,这几次大作业主要写了电信计费系统的主要功能,第一次大作业是座机计费功能,第二次大作业是手机计费功能,第三次大作业是短信计费的功能。这三次大作业主要考察了:容器的使用、抽象类、抛出异常、继承与多态、正则表达式,以及Data 类的使用等知识点。总的来说这三次PTA只要在第一次座机计费时搭建好了框架,后面只需要在第一次的基础上进行改进就好,难度总的来说中等偏上,题量适中。

二、设计与分析

7-1 电信计费系列1-座机计费

分数 80
全屏浏览题目
切换布局
实现一个简单的电信计费程序:
假设南昌市电信分公司针对市内座机用户采用的计费方式:

月租20元,接电话免费,市内拨打电话0.1元/分钟,省内长途0.3元/分钟,国内长途拨打0.6元/分钟。不足一分钟按一分钟计。
南昌市的区号:0791,江西省内各地市区号包括:0790~0799以及0701。

输入格式:

输入信息包括两种类型
1、逐行输入南昌市用户开户的信息,每行一个用户,
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐)
例如:u-079186300001 0
座机号码除区号外由是7-8位数字组成。
本题只考虑计费类型0-座机计费,电信系列2、3题会逐步增加计费类型。
2、逐行输入本月某些用户的通讯信息,通讯信息格式:
座机呼叫座机:t-主叫号码 接听号码 起始时间 结束时间
t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
以上四项内容之间以一个英文空格分隔,
时间必须符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat类。
以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“end”结束。
注意:
本题非法输入只做格式非法的判断,不做内容是否合理的判断(时间除外,否则无法计算),比如:
1、输入的所有通讯信息均认为是同一个月的通讯信息,不做日期是否在同一个月还是多个月的判定,直接将通讯费用累加,因此月租只计算一次。
2、记录中如果同一电话号码的多条通话记录时间出现重合,这种情况也不做判断,直接 计算每条记录的费用并累加。
3、用户区号不为南昌市的区号也作为正常用户处理。

输出格式:

根据输入的详细通讯信息,计算所有已开户的用户的当月费用(精确到小数点后2位,
单位元)。假设每个用户初始余额是100元。
每条通讯信息单独计费后累加,不是将所有时间累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。

错误处理:
输入数据中出现的不符合格式要求的行一律忽略。

建议类图:
参见图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的约束条件:必须是某一个用户的符合计费规则要求的所有记录。 LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是
座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。
(提示:可以从UserRecords类中获取各种类型的callRecords)。
 

后续扩展说明:
后续题目集将增加手机用户,手机用户的计费方式中除了与座机计费类似的主叫通话费之外,还包含市外接听电话的漫游费以及发短信的费用。在本题的设计时可统一考虑。
通话记录中,手机需要额外记录拨打/接听的地点的区号,比如:
座机打手机: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
短信的格式:m-主叫号码,接收号码,短信内容
m-18907910010 13305862264 welcome to jiangxi
m-13305862264 18907910010 thank you

输入样例:

在这里给出一组输入。例如:

u-079186300001 0
t-079186300001 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:25
end
 

输出样例:

在这里给出相应的输出。例如:

079186300001 3.0 77.0
代码如下:
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.Date;//Date是用于获取时间
import java.text.ParseException;//异常类
import java.text.SimpleDateFormat;//格式化时间 public class Main{
public static void main(String[] args) throws ParseException//异常处理
{
LandPhonelnlandRule landPhonelnlandRule =new LandPhonelnlandRule();
LandPhoneInCityRule landPhoneInCityRule =new LandPhoneInCityRule();
LandPhoneInProvinceRule landPhoneInProvinceRule=new LandPhoneInProvinceRule();
LandlinePhoneCharging landlinePhoneCharging=new LandlinePhoneCharging();
landlinePhoneCharging.getChargeRules().add(landPhoneInCityRule);
landlinePhoneCharging.getChargeRules().add(landPhoneInProvinceRule);
landlinePhoneCharging.getChargeRules().add(landPhonelnlandRule);
ArrayList<User> UserList=new ArrayList<>();
Scanner in =new Scanner(System.in);
String m=in.nextLine();
while(!m.equals("end"))
{
Judge judge=new Judge();
if(judge.isUserInformation(m))
{
String regex ="(0791)[\\d]{7,8}";
Pattern pattern =Pattern.compile(regex);
Matcher matcher=pattern.matcher(m);
while (matcher.find())
{
int flag=0;
for(User user:UserList)
{
if(user.getNumber().equals(matcher.group(0)))
{
flag=1;
break;
}
}
if(flag==0)
{
UserList.add(new User(matcher.group(0)));
}
}
}
if(judge.isCallingInformation(m))
{
String []a=m.split(" ");
try
{
SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
Date startTime =format.parse(a[2]+" "+a[3]);
Date endTime = format.parse(a[4]+" "+a[5]);
for(User user:UserList)
{
if(user.getNumber().equals(a[0].substring(2)))
{
if (judge.isInCityCode(a[1].substring(0,4)))
{
user.getUserRecords().addCallingInCityRecords(new CallRecord(startTime,endTime,a[0].substring(2,6),a[1].substring(0,4)));
}
else if(judge.isInProvinceCode(a[1].substring(0,4)))
{
user.getUserRecords().addCallingInProvinceRecords(new CallRecord(startTime,endTime,a[0].substring(2,6),a[1].substring(0,4)));
}
else
{
user.getUserRecords().addCallingInLandRecords(new CallRecord(startTime,endTime,a[0].substring(2,6),a[1].substring(0,4)));
}
}
}
}
catch(ParseException e)
{
e.printStackTrace();
}
}
m=in.nextLine();
}
for(User user:UserList)
{
user.setChargeMode(landlinePhoneCharging);
}
for(int i=0;i<UserList.size();i++)
{
int index=-1;
Double min = Double.parseDouble(UserList.get(i).getNumber());
for (int j = i+1;j<UserList.size();j++)
{
if(Double.parseDouble(UserList.get(j).getNumber())<min)
{
min = Double.parseDouble(UserList.get(j).getNumber());
index=j;
}
}
if(min!=Double.parseDouble(UserList.get(i).getNumber()))
{
User user = UserList.get(i);
UserList.set(i,UserList.get(index));
UserList.set(index,user);
}
}
for (User user:UserList)
{
System.out.printf("%s %.1f %.1f\n",user.getNumber(),user.getChargeMode().calCost(user.getUserRecords()),user.getBalance());
}
}
} abstract class ChargeRule
{
public double calCost(ArrayList<CallRecord> callRecords)
{
return 0;
}
} abstract class CallChargeRule extends ChargeRule
{
public double calCost(ArrayList<CallRecord> callRecords){
return 0;
}
} class CallRecord extends CommunicationRecord
{
private Date startTime;
private Date endTime;
private String callingAddressAreaCode;
private String answerAddressAreaCode; public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode)
{
this.startTime=startTime;
this.endTime = endTime;
this.callingAddressAreaCode = callingAddressAreaCode;
this.answerAddressAreaCode = answerAddressAreaCode;
}
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
{
private ArrayList<ChargeRule> chargeRules=new ArrayList<>();
public ArrayList<ChargeRule> getChargeRules()
{
return chargeRules;
} public void setChargeRules(ArrayList<ChargeRule> chargeRules)
{
this.chargeRules = chargeRules;
} public double calCost(UserRecords userRecords){
return 0;
}
public double getMonthlyRent()
{
return 0;
}
} abstract class CommunicationRecord
{
protected String callingNumber;
protected 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 Judge { public boolean isUserInformation(String s){
String pattern ="(u-0791)[\\d]{7,8}[\\s][0-2]";
return s.matches(pattern);
}
public boolean isCallingInformation(String s){
String pattern = "[t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s" +
"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.(((0?[13578]|1[02])\\.(0?" +
"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" +
"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" +
"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])\\s" +
"((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})\\.((([13578]|1[02])\\.(" +
"[1-9]|[12][0-9]|3[01]))|(([469]|11)\\.([1-9]|[12][0-9]|30))|(2\\.([1-9]|[1][0-9]|2[0-8]))))|(((" +
"[0-9]{2})([48]|[2468][048]|[13579][26])|(([48]|[2468][048]|[3579][26])00))\\.2\\.29))" +
"\\s([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])";
return s.matches(pattern);
}
public boolean isInCityCode(String s){
String pattern = "0791";
return s.equals(pattern);
}
public boolean isInProvinceCode(String s){
String pattern = "((0790)|(0701)|((079)[2-9]))";
return s.matches(pattern);
}
} class LandlinePhoneCharging extends ChargeMode
{
private double monthlyRent=20;
public double calCost(UserRecords userRecords)
{
double sum=0;
sum = getChargeRules().get(0).calCost(userRecords.getCallingInCityRecords())+getChargeRules().get(1).calCost(userRecords.getCallingInProvinceRecords())+getChargeRules().get(2).calCost(userRecords.getCallingInLandRecords());
return sum;
}
public double getMonthlyRent()
{
return monthlyRent;
}
} class LandPhoneCharging
{
private double monthly = 20; } class LandPhoneInCityRule extends CallChargeRule//市内
{
public double calCost(ArrayList<CallRecord> callRecords)
{
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords)
{
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if(second%60>0)
{
minute=second/60+1;
}
else
{
minute = second/60;
}
sumCost=sumCost+minute*0.1;
}
return sumCost;
}
} class LandPhoneInProvinceRule extends CallChargeRule//省内
{
public double calCost(ArrayList<CallRecord> callRecords){
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords
) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.3;
}
return sumCost;
}
}
class LandPhonelnlandRule extends CallChargeRule //省外
{
public double calCost(ArrayList<CallRecord> callRecords)
{
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords)
{
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0)
{
minute = second/60+1;
}
else
{
minute = second/60;
}
sumCost = sumCost+minute*0.6;
}
return sumCost;
}
} class MessageRecord extends CommunicationRecord
{
private String message; public String getMessage()
{
return message;
} public void setMessage(String message) {
this.message = message;
}
} class User
{
private UserRecords userRecords=new UserRecords();
private double balance=100;
private ChargeMode chargeMode;
private String number;
public User(String number)
{
this.number = number;
}
public double calBalance()
{
return 0;
}
public double calCost()
{
return 0;
}
public double getBalance()
{
return balance-chargeMode.calCost(userRecords)-chargeMode.getMonthlyRent();
}
public UserRecords getUserRecords()
{
return userRecords;
} public void setUserRecords(UserRecords userRecords)
{
this.userRecords = userRecords;
}
public ChargeMode getChargeMode() {
return chargeMode;
} public void setChargeMode(ChargeMode chargeMode)
{
this.chargeMode = chargeMode;
} public String getNumber()
{
return number;
} public void setNumber(String number)
{
this.number = number;
}
} class UserRecords
{
private ArrayList<CallRecord> callingInCityRecords = new ArrayList<>();
private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<>();
private ArrayList<CallRecord> callingInLandRecords = new ArrayList<>();
private ArrayList<CallRecord> answerInCityRecords = new ArrayList<>();
private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<>();
private ArrayList<CallRecord> answerInLandRecords = new ArrayList<>();
private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>();
private 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 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;
}
}

SourceMonitor的分析图如下:

分析如下:首先要建立User类,里面包含了建户的基本信息,号码,计费类型等属性。接着还需要一个类可以接收信息,处理信息,并将其所读取到的信息进行分别存储到两个容器,判断输入格式是否正确用正则表达式。然后将分类好的信息对应到每个用户之中,用UserRecord类来记录。通过对比输入信息中的号码与用户的开户号码,将通讯信息对应到每个用户下面,之后通过一系列计算将用户的电信费用展示出来。其中还需要我们创建新类,计算电话的时间差,以此来计算总费用,还要将ArrayList里的重复元素去掉。

踩坑心得:输入格式的正则表达式,要注意日期的合法性 ,注意题目要求,忽略重复开户的操作。

改进建议:在正则表达式的运用时太过于繁琐,需要改进。

7-2 多态测试

分数 20
全屏浏览题目
切换布局
作者 董卫萍
单位 绍兴文理学院元培学院

定义容器Container接口。模拟实现一个容器类层次结构,并进行接口的实现、抽象方法重写和多态机制测试。各容器类实现求表面积、体积的方法。

  1. 定义接口Container:
    属性:
    public static final double pi=3.1415926;
    抽象方法:
    public abstract double area();
    public abstract double volume();
    static double sumofArea(Container c[]);
    static double sumofVolume(Container c[]);
    其中两个静态方法分别计算返回容器数组中所有对象的面积之和、周长之和;
  2. 定义Cube类、Cylinder类均实现自Container接口。
    Cube类(属性:边长double类型)、Cylinder类(属性:底圆半径、高,double类型)。

输入格式:

第一行n表示对象个数,对象类型用cube、cylinder区分,cube表示立方体对象,后面输入边长,输入cylinder表示圆柱体对象,后面是底圆半径、高。

输出格式:

分别输出所有容器对象的表面积之和、体积之和,结果保留小数点后2位。

输入样例:

在这里给出一组输入。例如:

4
cube
15.7
cylinder
23.5 100
cube
46.8
cylinder
17.5 200

输出样例:

在这里给出相应的输出。例如:

56771.13
472290.12
 代码如下:
//import java.awt.geom.Area;//提供用于在与二维几何形状相关的对象上定义和执行操作的 Java 2D 类
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
int num ;
num=in.nextInt();
String b;
String m="cube";//立方体
String n="cylinder";//圆柱体
double areasum=0,volumesum=0;
for(int i=0;i<num;i++)
{
b=in.next();
if(!b.equals(m))//立方体
{
double c;
c=in.nextDouble();
double h;
h =in.nextDouble();
Cylinder cylinder=new Cylinder(c,h);
cylinder.area();
cylinder.volume();
areasum=areasum+ cylinder.area();
volumesum=volumesum+cylinder.volume();
}
if(!b.equals(n))//圆柱体
{
double a ;
a=in.nextDouble();
Cube cube=new Cube(a);
cube.area();
cube.volume();
areasum=areasum+cube.area();
volumesum=volumesum+cube.volume();
}
}
System.out.println(String.format("%.2f",areasum));
System.out.print(String.format("%.2f",volumesum));
} private static abstract class Container
{
public static final double pi=3.1415926;
public abstract double area();
public abstract double volume();
static double sumofarea (Container c[])
{
double s=Cube.sumofarea(c);
return 0;
}
static double sumofvolume(Container c[])
{
return 0;
}
private double radius;
public Container()
{
radius=0;
}
public Container(double a)
{
radius=a;
}
public double getRadius()
{
return radius;
}
}
public static class Cube extends Container
{
public Cube()
{
super();
}
public Cube(double a)
{
super(a);
}
public double area()
{
return super.getRadius()*super.getRadius()*6;
}
public double volume()
{
return super.getRadius()*super.getRadius()*super.getRadius();
}
}
public static class Cylinder extends Container
{
public double high;
public Cylinder()
{
super();
high=0;
}
public Cylinder(double a,double h)
{
super (a);
high=h;
}
public double gethigh()
{
return high;
}
public double area()
{
return pi*super.getRadius()*super.getRadius()*2+2*pi*super.getRadius()*high;
}
public double volume()
{
return pi*super.getRadius()*super.getRadius()*high;
}
}
}

SourceMonitor的分析图如下:

分析如下:这道题还是比较简单的,老师将主要的方法已经给出,我们只要简单的实现一些功能就好了。主要是对多态的使用和容器的使用进行练习。

踩坑心得:对于抽象类的使用不是很熟练。

改进建议:无

7-1 电信计费系列2-手机+座机计费

分数 80
全屏浏览题目
切换布局

实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
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)。
注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。

输入样例:

在这里给出一组输入。例如:

u-13811111111 1
t-13811111111 0791 13811111110 020 2022.1.3 08:00:00 2022.1.3 08:09:20
end
 

输出样例:

在这里给出相应的输出。例如:

13811111111 3.0 82.0
源码如下:
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat; public class Main {
public static void main(String[] args) throws ParseException {
Scanner input = new Scanner(System.in);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
simpleDateFormat.setLenient(false);
String str = input.nextLine();
String[] string = str.split(" ");
String[] strings = string[0].split("-");
String r1 = "u-0791[0-9]{7,8} 0";
String r2 = "u-1[0-9]{10} 1";
String r3 = "t-0791[0-9]{7,8} [0-9]{10,12} [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]) [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])";
String r4 = "t-0791[0-9]{7,8} 1[0-9]{10} [0-9]{3,4} [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]) [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])";
String r5 = "t-1[0-9]{10} [0-9]{3,4} 1[0-9]{10} [0-9]{3,4} [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]) [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])";
String r6 = "t-1[0-9]{10} [0-9]{3,4} [0-9]{10,12} [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]) [0-9]{4}\\.([1-9]|10|11|12)\\.([1-9]|[1-9][0-9]) ([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])";
String callnumber, anwsernumber, startTime, endTime, place, callPlace, anwserPlace;
CallRecord callRecord;
Date startDate, endDate;
ArrayList<User> users = new ArrayList<User>();
int flag; while(!str.equals("end")) {
flag = 0;
if(!str.equals("")) {
ParsePosition pos1 = new ParsePosition(0);
ParsePosition pos2 = new ParsePosition(0);
if(str.matches(r1)||str.matches(r2)) {
callnumber = strings[1];
User user = new User(callnumber);
if(!users.contains(user)) {
users.add(user);
}
}
else if(str.matches(r3)) {
callnumber = strings[1];
anwsernumber = string[1];
startTime = string[2] + " " + string[3];
endTime = string[4] + " " + string[5];
place = anwsernumber.substring(0, 4);
startDate = simpleDateFormat.parse(startTime, pos1);
endDate = simpleDateFormat.parse(endTime, pos2);
callRecord = new CallRecord(callnumber, anwsernumber, startDate, endDate); if(startDate!=null&&endDate!=null) {
for(int i=0;i<users.size();i++) {
if(users.get(i).getNumber().equals(callnumber)) {
if(place.equals("0791")) {
users.get(i).getUserRecords().addcallingInCityRecords(callRecord);
}
else if(place.equals("0790")||place.equals("0792")||place.equals("0793")||place.equals("0794")||place.equals("0795")
||place.equals("0796")||place.equals("0797")||place.equals("0798")||place.equals("0799")||place.equals("0701")) {
users.get(i).getUserRecords().addcallingInProvinceRecords(callRecord);
}
else {
users.get(i).getUserRecords().addcallingInLandRecords(callRecord);
}
break;
}
}
}
}
else if(str.matches(r4)) {
callnumber = strings[1];
anwsernumber = string[1];
anwserPlace = string[2];
startTime = string[3] + " " + string[4];
endTime = string[5] + " " + string[6];
startDate = simpleDateFormat.parse(startTime, pos1);
endDate = simpleDateFormat.parse(endTime, pos2);
callRecord = new CallRecord(callnumber, anwsernumber, startDate, endDate); if(startDate!=null&&endDate!=null) {
for(int i=0;i<users.size();i++) {
if(users.get(i).getNumber().equals(callnumber)) {
if(anwserPlace.equals("0791")) {
users.get(i).getUserRecords().addcallingInCityRecords(callRecord);
}
else if(anwserPlace.equals("0790")||anwserPlace.equals("0792")||anwserPlace.equals("0793")||anwserPlace.equals("0794")||anwserPlace.equals("0795")
||anwsernumber.equals("0796")||anwserPlace.equals("0797")||anwserPlace.equals("0798")||anwserPlace.equals("0799")||anwserPlace.equals("0701")) {
users.get(i).getUserRecords().addcallingInProvinceRecords(callRecord);
}
else {
users.get(i).getUserRecords().addcallingInLandRecords(callRecord);
for(int j=0;j<users.size();j++) {
if(users.get(j).getNumber().equals(anwsernumber)) {
users.get(j).getUserRecords().addPhoneProvinceAnwseringInLandRecords(callRecord);
}
}
}
flag = 1;
break;
}
}
if(flag==0) {
for(int j=0;j<users.size();j++) {
if(users.get(j).getNumber().equals(anwsernumber)) {
if(anwserPlace.equals("0791")||anwserPlace.equals("0790")||anwserPlace.equals("0792")||anwserPlace.equals("0793")||anwserPlace.equals("0794")||anwserPlace.equals("0795")
||anwsernumber.equals("0796")||anwserPlace.equals("0797")||anwserPlace.equals("0798")||anwserPlace.equals("0799")||anwserPlace.equals("0701")) {
break;
}
else {
users.get(j).getUserRecords().addPhoneProvinceAnwseringInLandRecords(callRecord);
break;
}
}
}
}
}
}
else if(str.matches(r5)) {
callnumber = strings[1];
callPlace = string[1];
anwsernumber = string[2];
anwserPlace = string[3];
startTime = string[4] + " " + string[5];
endTime = string[6] + " " + string[7];
startDate = simpleDateFormat.parse(startTime, pos1);
endDate = simpleDateFormat.parse(endTime, pos2);
callRecord = new CallRecord(callnumber, anwsernumber, startDate, endDate); if(startDate!=null&&endDate!=null) {
for(int i=0;i<users.size();i++) {
if(users.get(i).getNumber().equals(callnumber)) {
if(callPlace.equals("0791")&&anwserPlace.equals("0791")) {
users.get(i).getUserRecords().addPhoneCityCallingInCityRecords(callRecord);
}
else if(callPlace.equals("0791")&&(anwserPlace.equals("0790")||anwserPlace.equals("0792")||anwserPlace.equals("0793")||anwserPlace.equals("0794")||anwserPlace.equals("0795")
||anwserPlace.equals("0796")||anwserPlace.equals("0797")||anwserPlace.equals("0798")||anwserPlace.equals("0799")||anwserPlace.equals("0701"))) {
users.get(i).getUserRecords().addPhoneCityCallingInProvinceRecords(callRecord);
}
else if(callPlace.equals("0791")) {
users.get(i).getUserRecords().addPhoneCityCallingInLandRecords(callRecord);
for(int j=0;j<users.size();j++) {
if(users.get(j).getNumber().equals(anwsernumber)) {
users.get(j).getUserRecords().addPhoneProvinceAnwseringInLandRecords(callRecord);
break;
}
}
}
else if((callPlace.equals("0790")||callPlace.equals("0792")||callPlace.equals("0793")||callPlace.equals("0794")||callPlace.equals("0795")
||callPlace.equals("0796")||callPlace.equals("0797")||callPlace.equals("0798")||callPlace.equals("0799")||callPlace.equals("0701"))
&&(anwserPlace.equals("0791")||anwserPlace.equals("0790")||anwserPlace.equals("0792")||anwserPlace.equals("0793")||anwserPlace.equals("0794")||anwserPlace.equals("0795")
||anwserPlace.equals("0796")||anwserPlace.equals("0797")||anwserPlace.equals("0798")||anwserPlace.equals("0799")||anwserPlace.equals("0701"))) {
users.get(i).getUserRecords().addPhoneProvinceCallingInLandRecords(callRecord);
}
else if(callPlace.equals("0790")||callPlace.equals("0792")||callPlace.equals("0793")||callPlace.equals("0794")||callPlace.equals("0795")
||callPlace.equals("0796")||callPlace.equals("0797")||callPlace.equals("0798")||callPlace.equals("0799")||callPlace.equals("0701")) {
users.get(i).getUserRecords().addPhoneProvinceCallingInLandRecords(callRecord);
for(int j=0;j<users.size();j++) {
if(users.get(j).getNumber().equals(anwsernumber)) {
users.get(j).getUserRecords().addPhoneProvinceAnwseringInLandRecords(callRecord);
break;
}
}
}
else if(anwserPlace.equals("0791")||anwserPlace.equals("0790")||anwserPlace.equals("0792")||anwserPlace.equals("0793")||anwserPlace.equals("0794")||anwserPlace.equals("0795")
||anwserPlace.equals("0796")||anwserPlace.equals("0797")||anwserPlace.equals("0798")||anwserPlace.equals("0799")||anwserPlace.equals("0701")) {
users.get(i).getUserRecords().addPhoneLandCallingInLandRecords(callRecord);
}
else {
users.get(i).getUserRecords().addPhoneLandCallingInLandRecords(callRecord);
for(int j=0;j<users.size();j++) {
if(users.get(j).getNumber().equals(anwsernumber)) {
users.get(j).getUserRecords().addPhoneProvinceAnwseringInLandRecords(callRecord);
break;
}
}
}
flag = 1;
break;
}
}
if(flag==0) {
for(int j=0;j<users.size();j++) {
if(users.get(j).getNumber().equals(anwsernumber)) {
if(anwserPlace.equals("0791")||anwserPlace.equals("0790")||anwserPlace.equals("0792")||anwserPlace.equals("0793")||anwserPlace.equals("0794")||anwserPlace.equals("0795")
||anwserPlace.equals("0796")||anwserPlace.equals("0797")||anwserPlace.equals("0798")||anwserPlace.equals("0799")||anwserPlace.equals("0701")) {
break;
}
else {
users.get(j).getUserRecords().addPhoneProvinceAnwseringInLandRecords(callRecord);
break;
}
}
}
}
}
}
else if(str.matches(r6)) {
callnumber = strings[1];
callPlace = string[1];
anwsernumber = string[2];
anwserPlace = anwsernumber.substring(0, 4);
startTime = string[3] + " " + string[4];
endTime = string[5] + " " + string[6];
startDate = simpleDateFormat.parse(startTime, pos1);
endDate = simpleDateFormat.parse(endTime, pos2);
callRecord = new CallRecord(callnumber, anwsernumber, startDate, endDate); if(startDate!=null&&endDate!=null) {
for(int i=0;i<users.size();i++) {
if(users.get(i).getNumber().equals(callnumber)) {
if(callPlace.equals("0791")) {
if(anwserPlace.equals("0791")) {
users.get(i).getUserRecords().addPhoneCityCallingInCityRecords(callRecord);
}
else if(anwserPlace.equals("0790")||anwserPlace.equals("0792")||anwserPlace.equals("0793")||anwserPlace.equals("0794")||anwserPlace.equals("0795")
||anwserPlace.equals("0796")||anwserPlace.equals("0797")||anwserPlace.equals("0798")||anwserPlace.equals("0799")||anwserPlace.equals("0701")) {
users.get(i).getUserRecords().addPhoneCityCallingInProvinceRecords(callRecord);
}
else {
users.get(i).getUserRecords().addPhoneCityCallingInLandRecords(callRecord);
}
}
else if(callPlace.equals("0790")||callPlace.equals("0792")||callPlace.equals("0793")||callPlace.equals("0794")||callPlace.equals("0795")
||callPlace.equals("0796")||callPlace.equals("0797")||callPlace.equals("0798")||callPlace.equals("0799")||callPlace.equals("0701")) {
users.get(i).getUserRecords().addPhoneProvinceCallingInLandRecords(callRecord);
}
else {
users.get(i).getUserRecords().addPhoneLandCallingInLandRecords(callRecord);
}
break;
}
}
}
}
}
str = input.nextLine();
string = str.split(" ");
strings = string[0].split("-");
}
Collections.sort(users, new Comparator<User>() {
@Override
public int compare(User user1, User user2) {
return user1.getNumber().compareTo(user2.getNumber());
}
});
for(int j=0;j<users.size();j++) {
if(users.get(j).getNumber().charAt(0)=='0') {
System.out.println(users.get(j).getNumber() + " " + String.format("%.1f", users.get(j).calCost()) + " " + String.format("%.1f", users.get(j).calBalance()));
}
else {
System.out.println(users.get(j).getNumber() + " " + String.format("%.1f", users.get(j).phoneCost()) + " " + String.format("%.1f", users.get(j).phoneBalance()));
}
}
}
}
class User {
private UserRecords userRecords = new UserRecords();
private double balance = 100;
private ChargeMode landLinePhonechargeMode = new LandLinePoneCharge();
private ChargeMode phoneChargeMode = new PhoneCharge();
private String number; public User() { super();
} public User(String number) {
super();
this.number = number;
} 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 ChargeMode getLandLinePhonechargeMode() {
return landLinePhonechargeMode;
} public void setLandLinePhonechargeMode(ChargeMode landLinePhonechargeMode) {
this.landLinePhonechargeMode = landLinePhonechargeMode;
} public ChargeMode getPhoneChargeMode() {
return phoneChargeMode;
} public void setPhoneChargeMode(ChargeMode phoneChargeMode) {
this.phoneChargeMode = phoneChargeMode;
} public String getNumber() {
return number;
} public void setNumber(String number) {
this.number = number;
} public double calBalance() {
return getBalance() - calCost() - landLinePhonechargeMode.getMonthlyRent();
} public double calCost() {
return landLinePhonechargeMode.calCost(userRecords);
} public double phoneBalance() {
return getBalance() - phoneCost() - phoneChargeMode.getMonthlyRent();
} public double phoneCost() {
return phoneChargeMode.calCost(userRecords);
} @Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o instanceof User) {
User user = (User) o;
return number.equals(user.getNumber());
}
return false;
}
}
abstract class ChargeMode {
private ArrayList<CallChargeRule> callChargeRules; public ArrayList<CallChargeRule> getCallChargeRules() {
return callChargeRules;
} public void setCallChargeRules(ArrayList<CallChargeRule> callChargeRules) {
this.callChargeRules = callChargeRules;
} public abstract double calCost(UserRecords userRecords); public abstract double getMonthlyRent();
}
class LandLinePoneCharge extends ChargeMode {
private double monthlyRent = 20;
private CallChargeRule landPhoneInCityRule = new LandPhoneInCityRule();
private CallChargeRule landPhoneInProvinceRule = new LandPhoneInProvinceRule();
private CallChargeRule landPhoneInLandRule = new LandPhoneInLandRule(); public LandLinePoneCharge() {
super();
} @Override
public double calCost(UserRecords userRecords) {
double cost = 0;
cost += landPhoneInCityRule.calCost(userRecords.getCallingInCityRecords())
+ landPhoneInProvinceRule.calCost(userRecords.getCallingInProvinceRecords())
+ landPhoneInLandRule.calCost(userRecords.getCallingInLandRecords());
return cost;
} @Override
public double getMonthlyRent() {
return monthlyRent;
} }
class PhoneCharge extends ChargeMode {
private double monthlyRent = 15;
private CallChargeRule phoneCityCallingInCityRule = new PhoneCityCallingInCityRule();
private CallChargeRule phoneCityCallingInProvinceRule = new PhoneCityCallingInProvinceRule();
private CallChargeRule phoneCityCallingInLandRule = new PhoneCityCallingInLandRule();
private CallChargeRule phoneProvinceCallingInLandRule = new PhoneProvinceCallingInLandRule();
private CallChargeRule phoneProvinceAnwseringInLandRule = new PhoneProvinceAnwseringInLandRule();
private CallChargeRule phoneLandCallingInLandRule = new PhoneLandCallingInLandRule(); public PhoneCharge() {
super();
} @Override
public double calCost(UserRecords userRecords) {
return phoneCityCallingInCityRule.calCost(userRecords.getPhoneCityCallingInCityRecords()) + phoneCityCallingInProvinceRule.calCost(userRecords.getPhoneCityCallingInProvinceRecords())
+ phoneCityCallingInLandRule.calCost(userRecords.getPhoneCityCallingInLandRecords()) + phoneProvinceCallingInLandRule.calCost(userRecords.getPhoneProvinceCallingInLandRecords())
+ phoneProvinceAnwseringInLandRule.calCost(userRecords.getPhoneProvinceAnwseringInLandRecords()) + phoneLandCallingInLandRule.calCost(userRecords.getPhoneLandCallingInLandRecords());
} @Override
public double getMonthlyRent() {
return monthlyRent;
} }
class UserRecords {
private ArrayList<CallRecord> callingInCityRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> callingInLandRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> phoneCityCallingInCityRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> phoneCityCallingInProvinceRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> phoneCityCallingInLandRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> phoneProvinceCallingInLandRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> phoneProvinceAnwseringInLandRecords = new ArrayList<CallRecord>();
private ArrayList<CallRecord> phoneLandCallingInLandRecords = new ArrayList<CallRecord>(); public UserRecords() {
super();
} public ArrayList<CallRecord> getPhoneCityCallingInCityRecords() {
return phoneCityCallingInCityRecords;
} public ArrayList<CallRecord> getPhoneCityCallingInProvinceRecords() {
return phoneCityCallingInProvinceRecords;
} public ArrayList<CallRecord> getPhoneCityCallingInLandRecords() {
return phoneCityCallingInLandRecords;
} public ArrayList<CallRecord> getPhoneProvinceCallingInLandRecords() {
return phoneProvinceCallingInLandRecords;
} public ArrayList<CallRecord> getPhoneProvinceAnwseringInLandRecords() {
return phoneProvinceAnwseringInLandRecords;
} public ArrayList<CallRecord> getPhoneLandCallingInLandRecords() {
return phoneLandCallingInLandRecords;
} public ArrayList<CallRecord> getCallingInCityRecords() {
return callingInCityRecords;
} public ArrayList<CallRecord> getCallingInProvinceRecords() {
return callingInProvinceRecords;
} public ArrayList<CallRecord> getCallingInLandRecords() {
return callingInLandRecords;
} public void addcallingInCityRecords(CallRecord callRecord) {
getCallingInCityRecords().add(callRecord);
} public void addcallingInProvinceRecords(CallRecord callRecord) {
getCallingInProvinceRecords().add(callRecord);
} public void addcallingInLandRecords(CallRecord callRecord) {
getCallingInLandRecords().add(callRecord);
} public void addPhoneCityCallingInCityRecords(CallRecord callRecord) {
getPhoneCityCallingInCityRecords().add(callRecord);
} public void addPhoneCityCallingInProvinceRecords(CallRecord callRecord) {
getPhoneCityCallingInProvinceRecords().add(callRecord);
} public void addPhoneCityCallingInLandRecords(CallRecord callRecord) {
getPhoneCityCallingInLandRecords().add(callRecord);
} public void addPhoneProvinceCallingInLandRecords(CallRecord callRecord) {
getPhoneProvinceCallingInLandRecords().add(callRecord);
} public void addPhoneProvinceAnwseringInLandRecords(CallRecord callRecord) {
getPhoneProvinceAnwseringInLandRecords().add(callRecord);
} public void addPhoneLandCallingInLandRecords(CallRecord callRecord) {
getPhoneLandCallingInLandRecords().add(callRecord);
}
}
abstract class CommunicationRecord {
private String callingNumber;
private String answerNumber; public CommunicationRecord(String callingNumber, String answerNumber) {
super();
this.callingNumber = callingNumber;
this.answerNumber = 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 CallRecord extends CommunicationRecord {
private Date startTime;
private Date endTime; public CallRecord(String callingNumber, String answerNumber, Date startTime, Date endTime) {
super(callingNumber, answerNumber);
this.startTime = startTime;
this.endTime = endTime;
} 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 double getTime() {
long time;
time = (endTime.getTime() - startTime.getTime()) / 1000;
if(time%60==0) {
time /= 60;
}
else {
time = time / 60 + 1;
}
return (double)time;
} }
abstract class ChargeRule{ }
abstract class CallChargeRule extends ChargeRule { public abstract double calCost(ArrayList<CallRecord> callRecords); }
class LandPhoneInCityRule extends CallChargeRule { //座机市内拨打电话 public LandPhoneInCityRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double city = 0;
for(int i=0;i<callRecords.size();i++) {
city += callRecords.get(i).getTime() * 0.1;
}
return city;
} }
class LandPhoneInProvinceRule extends CallChargeRule { //座机省内长途 public LandPhoneInProvinceRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double province = 0;
for(int i=0;i<callRecords.size();i++) {
province += callRecords.get(i).getTime() * 0.3;
}
return province;
} }
class LandPhoneInLandRule extends CallChargeRule { //座机国内长途 public LandPhoneInLandRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double land = 0;
for(int i=0;i<callRecords.size();i++) {
land += callRecords.get(i).getTime() * 0.6;
}
return land;
} }
class PhoneCityCallingInCityRule extends CallChargeRule { //手机市内拨打市内电话 public PhoneCityCallingInCityRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost = 0;
for(int i=0;i<callRecords.size();i++) {
cost += callRecords.get(i).getTime() * 0.1;
}
return cost;
} }
class PhoneCityCallingInProvinceRule extends CallChargeRule { //手机市内拨打省内电话 public PhoneCityCallingInProvinceRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost = 0;
for(int i=0;i<callRecords.size();i++) {
cost += callRecords.get(i).getTime() * 0.2;
}
return cost;
} }
class PhoneCityCallingInLandRule extends CallChargeRule { //手机市内拨打省外电话 public PhoneCityCallingInLandRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost = 0;
for(int i=0;i<callRecords.size();i++) {
cost += callRecords.get(i).getTime() * 0.3;
}
return cost;
} }
class PhoneProvinceCallingInLandRule extends CallChargeRule { //手机省内漫游打电话 public PhoneProvinceCallingInLandRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost = 0;
for(int i=0;i<callRecords.size();i++) {
cost += callRecords.get(i).getTime() * 0.3;
}
return cost;
} }
class PhoneProvinceAnwseringInLandRule extends CallChargeRule { //手机省外漫游接听 public PhoneProvinceAnwseringInLandRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost = 0;
for(int i=0;i<callRecords.size();i++) {
cost += callRecords.get(i).getTime() * 0.3;
}
return cost;
} }
class PhoneLandCallingInLandRule extends CallChargeRule { //手机省外漫游拨打 public PhoneLandCallingInLandRule() {
super();
} @Override
public double calCost(ArrayList<CallRecord> callRecords) {
double cost = 0;
for(int i=0;i<callRecords.size();i++) {
cost += callRecords.get(i).getTime() * 0.6;
}
return cost;
} }

SourceMonitor的分析图如下:

分析如下:这道题的计费形式对于上一次的计费多了很多种,主要是手机的计费规则多了省内漫游和省外漫游。手机计费不是按照开户时的地址进行计算,而是根据拨打人拨打时所在的区号以及接听人接听所在区号进行计费。在上题的基础上,增加储存手机用户的容器,增加相应手机计费规则,以及判断手机通讯信息的正则表达式,储存手机用户的方式和上题储存座机用户的方式基本一致,根据拨打人所在区号根据接听人的区号判断是市内省内还是国内长途信息等类型,在用户信息里建立对应的容器储存它们。

踩坑心得:在计费方面,由于存在座机打手机,手机打手机,手机打座机等,所以在数据储存时,他们的信息格式各不相同,在信息储存过程中需要注意格式。

改进建议:从上图的分析情况来看,代码整体的复杂度太高,可读性不强,应再次改进,降低复杂度,使代码更简洁。

7-2 sdut-Collection-sort--C~K的班级(II)

分数 10
全屏浏览题目
切换布局
作者 周雪芹
单位 山东理工大学

经过不懈的努力,C~K终于当上了班主任。

现在他要统计班里学生的名单,但是C~K在教务系统中导出班级名单时出了问题,发现会有同学的信息重复,现在他想把重复的同学信息删掉,只保留一个,
但是工作量太大了,所以找到了会编程的你,你能帮他解决这个问题吗?

输入格式:

第一行输入一个N,代表C~K导出的名单共有N行(N<100000).

接下来的N行,每一行包括一个同学的信息,学号 姓名 年龄 性别。

输出格式:

第一行输出一个n,代表删除重复名字后C~K的班级共有几人。

接下来的n行,输出每一个同学的信息,输出按照学号从小到大的顺序。

输入样例:

6
0001 MeiK 20 M
0001 MeiK 20 M
0002 sdk2 21 M
0002 sdk2 21 M
0002 sdk2 21 M
0000 blf2 22 F
 

输出样例:

3
0000 blf2 22 F
0001 MeiK 20 M
0002 sdk2 21 M

源码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
public class Main{
public static void main(String args[]){
HashMap<String,Student> students=new HashMap<String,Student>();
Scanner in =new Scanner(System.in);
int n=in.nextInt();
String s=new String();
s=in.nextLine();
for(int i=0;i<n;i++)
{
s=in.nextLine();
String[] ns=s.split(" ");
Student s1=new Student(ns[0],ns[1],ns[2],ns[3]);
students.put(s1.sno,s1);
}
HashMap<String,Student> sortHashMap = sortHashMap(students);
System.out.println(sortHashMap.size());//返回所有value值
for(Student value:sortHashMap.values())
{
System.out.println(value.sno+" "+value.name+" "+value.age+" "+value.sex);
}
}
public static HashMap<String,Student> sortHashMap(HashMap<String,Student> map)
{
Set<Map.Entry<String,Student>> entrySet=map.entrySet();// 首先拿到 map 的键值对集合
//将 set 集合转为 List 集合,为了使用工具类的排序方法
List<Map.Entry<String,Student>> list=new ArrayList<Map.Entry<String,Student>>(entrySet);
// 使用 Collections 集合工具类对 list 进行排序,排序规则使用匿名内部类来实现
Collections.sort(list, new Comparator<Map.Entry<String,Student>>()
{
public int compare(Map.Entry<String,Student>o1,Map.Entry<String,Student>o2)
{
//按照要求根据 User 的 age 的升序进行排,如果是倒序就是o2-o1
int flag = new Integer(o1.getValue().sno.compareTo(o2.getValue().sno));
return flag;
}
});
//创建一个新的有序的 HashMap子类的集合
LinkedHashMap<String,Student> linkedHashMap = new LinkedHashMap<String,Student>();
//将 List 中的数据存储在 LinkedHashMap中
for(Map.Entry<String,Student> entry : list)
{
linkedHashMap.put(entry.getKey(), entry.getValue());
}
return linkedHashMap;
}
} class Student
{
String name;
String sno;
String sex;
String age;
public Student(String sno,String name,String age,String sex){
this.age=age;
this.name=name;
this.sno=sno;
this.sex=sex;
}
}

SourceMonitor的分析图如下:

分析如下:这道题主要考察了对于容器HashMap的使用,集合容器,不会让元素重复出现,是个很好的特点。

踩坑心得:其中关于元素的排序,我是在网上查阅了相关资料进行理解的。

改进建议:无

7-3 阅读程序,按照题目需求修改程序

分数 10
全屏浏览题目
切换布局
作者 肖斌
单位 西南石油大学
功能需求:
使用集合存储3个员工的信息(有序);
通过迭代器依次找出所有的员工。
提示:学生复制以下代码到编程区,并按需求进行调试修改。

// 1、导入相关包 //定义员工类
class Employee { private String name;
private int age; public Employee() {
super();
} public Employee(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
} //主函数
public class Main { public static void main(String[] args) {
// 1、创建有序集合对象
Collection c ; // 创建3个员工元素对象
for (int i = 0; i < 3; i++) {
Scanner sc = new Scanner(System.in);
String employeeName = sc.nextLine();
int employeeAge = sc.nextInt(); Employee employee = new Employee(employeeName, employeeAge);
c.add(employee);
} // 2、创建迭代器遍历集合
Iterator it; //3、遍历
while (it.hasnext) { //4、集合中对象未知,向下转型
Employee e = it.next(); System.out.println(e.getName() + "---" + e.getAge());
}
} }

输入样例

在这里给出一组输入。例如:

zs
10
ls
20
ww
30

在这里给出相应的输出。例如:

zs---10
ls---20
ww---30
代码如下:
import java.util.Iterator; // 引入 Iterator 类
import java.util.Scanner;
import java.util.Collection;
import java.util.ArrayList;
// 1、导入相关包 //定义员工类
class Employee { private String name;
private int age; public Employee() {
super();
} public Employee(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
} //主函数
public class Main { public static void main(String[] args) {
// 1、创建有序集合对象
Collection c = new ArrayList(); // 创建3个员工元素对象
for (int i = 0; i < 3; i++) {
Scanner sc = new Scanner(System.in);
String employeeName = sc.nextLine();
int employeeAge = sc.nextInt(); Employee employee = new Employee(employeeName, employeeAge);
c.add(employee);
} // 2、创建迭代器遍历集合
Iterator it = c.iterator(); //3、遍历
while (it.hasNext()) { //4、集合中对象未知,向下转型
Employee e = (Employee)it.next(); System.out.println(e.getName() + "---" + e.getAge());
}
} }

SourceMonitor的分析图如下:

分析如下:这道题属于代码修改,题目已经给出了代码,只需要利用IDEA的修改功能就可以完成。

7-1 电信计费系列3-短信计费

分数 50
全屏浏览题目
切换布局
作者 蔡轲
单位 南昌航空大学

实现一个简单的电信计费程序,针对手机的短信采用如下计费方式
1、接收短信免费,发送短信0.1元/条,超过3条0.2元/条,超过5条0.3元/条。
2、如果一次发送短信的字符数量超过10个,按每10个字符一条短信进行计算。

输入:
输入信息包括两种类型
1、逐行输入南昌市手机用户开户的信息,每行一个用户。
格式:u-号码 计费类型 (计费类型包括:0-座机 1-手机实时计费 2-手机A套餐 3-手机短信计费)
例如:u-13305862264 3
座机号码由区号和电话号码拼接而成,电话号码包含7-8位数字,区号最高位是0。
手机号码由11位数字构成,最高位是1。
本题只针对类型3-手机短信计费。
2、逐行输入本月某些用户的短信信息,短信的格式:
m-主叫号码,接收号码,短信内容 (短信内容只能由数字、字母、空格、英文逗号、英文句号组成)
m-18907910010 13305862264 welcome to jiangxi.
m-13305862264 18907910010 thank you.

注意:以上两类信息,先输入所有开户信息,再输入所有通讯信息,最后一行以“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(短信记录)是它的子类。
 

图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。
SendMessageRule是发送短信的计费规则类,用于计算发送短信的费用。
LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。

(提示:可以从UserRecords类中获取各种类型的callRecords)。
 

注意:以上图中所定义的类不是限定要求,根据实际需要自行补充或修改。

输入样例:

在这里给出一组输入。例如:

u-18907910010 3
m-18907910010 13305862264 aaaaaaaaaaaaaaaaaaaaaaa
end

输出样例:

在这里给出相应的输出。例如:

18907910010 0.3 99.7

### 输入样例1:

在这里给出一组输入。例如:
u-18907910010 3
m-18907910010 13305862264 aaaaaaaaaaaa
m-18907910010 13305862264 aaaaaaa.
m-18907910010 13305862264 bb,bbbb
end

输出样例1:

在这里给出相应的输出。例如:

18907910010 0.5 99.5
代码如下:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern; public class Main {
public static void main(String[] args) throws ParseException {
ArrayList<User> User1List = new ArrayList<>();
ArrayList<MessageChargeRule> messageChargeRules = new ArrayList<>();
SendMessageRule sendMessageRule = new SendMessageRule();
MessageCharging messageCharging = new MessageCharging();
messageCharging.getMessageChargeRules().add(sendMessageRule);
Scanner in = new Scanner(System.in);
String m = in.nextLine();
int flag;
while (!m.equals("end")) {
Judge judge = new Judge(); if (judge.isUser1Information(m)) {
String regex = "[1][\\d]{10}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(m);
while (matcher.find()) {
flag = 0;
for (User user : User1List ) {
if (user.getNumber().equals(matcher.group(0))) {
flag = 1;
break;
}
}
if (flag == 0) {
User1List.add(new User(matcher.group(0)));
}
}
}
if (judge.isMessageInformation(m)){
for (User user:User1List
) {
if (user.getNumber().equals(m.substring(2,13))){
user.getUserRecords().addSendMessageRecords(new MessageRecord(m.substring(26)));
}
}
}
m = in.nextLine();
}
for (User user:User1List ) {
user.setChargeMode(messageCharging);
} for (int i = 0; i < User1List.size(); i++) {
int index = -1;
Double min = Double.parseDouble(User1List.get(i).getNumber());
for (int j = i + 1; j < User1List.size(); j++) {
if (Double.parseDouble(User1List.get(j).getNumber()) < min) {
min = Double.parseDouble(User1List.get(j).getNumber());
index = j;
}
}
if (min != Double.parseDouble(User1List.get(i).getNumber())) {
User user = User1List.get(i);
User1List.set(i, User1List.get(index));
User1List.set(index, user);
}
}
for (User user:User1List
) {
System.out.printf("%s %.1f %.1f\n",user.getNumber(),user.getChargeMode().calCost(user.getUserRecords()),user.getMessageBalance());
}
}
}
class MessageCharging extends ChargeMode{
public double calCost(UserRecords userRecords){
return getMessageChargeRules().get(0).calCost(userRecords.getSendMessageRecords());
}
}
abstract class CallChargeRule extends ChargeRule{
public double calCost(ArrayList<CallRecord> callRecords){
return 0;
}
}
abstract class MessageChargeRule extends ChargeRule{
public double calCost(ArrayList<MessageRecord> messageRecords){
return 0;
}
}
class SendMessageRule extends MessageChargeRule{
public double calCost(ArrayList<MessageRecord> messageRecords){
int count = 0;
double sum;
for (MessageRecord messageRecord:messageRecords ) {
if (messageRecord.getMessage().length()%10!=0){
count+=messageRecord.getMessage().length()/10+1;
}
else {
count+=messageRecord.getMessage().length()/10;
}
}
if (count<=3){
sum=count*0.1;
}
else if (count>3&&count<=5){
sum=0.3+(count-3)*0.2;
}
else {
sum=0.3+0.4+(count-5)*0.3;
}
return sum;
}
}
class CallRecord extends CommunicationRecord{
private Date startTime;
private Date endTime;
private String callingAddressAreaCode;
private String answerAddressAreaCode; public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String answerAddressAreaCode) {
this.startTime = startTime;
this.endTime = endTime;
this.callingAddressAreaCode = callingAddressAreaCode;
this.answerAddressAreaCode = answerAddressAreaCode;
} 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 {
private ArrayList<ChargeRule> chargeRules = new ArrayList<>();
private ArrayList<ChargeRule> chargeRules1 = new ArrayList<>();
private ArrayList<MessageChargeRule> messageChargeRules = new ArrayList<>(); public void setChargeRules1(ArrayList<ChargeRule> chargeRules1) {
this.chargeRules1 = chargeRules1;
} public ArrayList<MessageChargeRule> getMessageChargeRules() {
return messageChargeRules;
} public void setMessageChargeRules(ArrayList<MessageChargeRule> messageChargeRules) {
this.messageChargeRules = messageChargeRules;
} public ArrayList<ChargeRule> getChargeRules1() {
return chargeRules1;
}
public ArrayList<ChargeRule> getChargeRules() {
return chargeRules;
} public void setChargeRules(ArrayList<ChargeRule> chargeRules) {
this.chargeRules = chargeRules;
} public double calCost(UserRecords userRecords){
return 0;
}
public double getMonthlyRent(){
return 0;
}
}
abstract class ChargeRule { }
abstract class CommunicationRecord {
protected String callingNumber;
protected 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 Judge {
public boolean isMessageInformation(String s){
String pattern = "(m-)1[\\d]{10}\\s1[\\d]{10}\\s[A-Za-z0-9\\s,.]+";
return s.matches(pattern);
}
public boolean isUser1Information(String s){
String pattern = "(u-)[1][\\d]{10}[\\s][0-3]";
return s.matches(pattern);
}
}
class LandlinePhoneCharging extends ChargeMode{
private double monthlyRent = 20; public double calCost(UserRecords userRecords){ return 0;
}
public double getMonthlyRent(){
return monthlyRent;
}
}
class LandPhoneCharging {
private double monthly = 20; }
class LandPhoneInCityRule extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.1;
}
return sumCost;
}
}
class LandPhoneInProvinceRule extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords){
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords
) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.3;
}
return sumCost;
}
}
class LandPhonelnlandRule extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords){
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords
) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.6;
}
return sumCost;
}
}
class MessageRecord extends CommunicationRecord{
private String message; public MessageRecord(String message) {
this.message = message;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
}
}
class User {
private UserRecords userRecords = new UserRecords();
private double balance = 100;
private ChargeMode chargeMode;
private String number;
public User(String number) {
this.number = number;
}
public double getMessageBalance(){
return balance-chargeMode.calCost(userRecords);
}
public double getBalance() {
return balance-chargeMode.calCost(userRecords)-chargeMode.getMonthlyRent();
} public UserRecords getUserRecords() {
return userRecords;
} public void setUserRecords(UserRecords userRecords) {
this.userRecords = userRecords;
} public ChargeMode getChargeMode() {
return chargeMode;
} public void setChargeMode(ChargeMode chargeMode) {
this.chargeMode = chargeMode;
} public String getNumber() {
return number;
} public void setNumber(String number) {
this.number = number;
}
}
class UserRecords {
private ArrayList<CallRecord> callingInCityRecords = new ArrayList<>();
private ArrayList<CallRecord> callingInProvinceRecords = new ArrayList<>();
private ArrayList<CallRecord> callingInLandRecords = new ArrayList<>();
private ArrayList<CallRecord> answerInCityRecords = new ArrayList<>();
private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<>();
private ArrayList<CallRecord> answerInLandRecords = new ArrayList<>();
private ArrayList<CallRecord> manYouInProvinceRecords = new ArrayList<>();
private ArrayList<CallRecord> manYouOutProvinceRecords = new ArrayList<>();
private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<>();
private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<>(); public void addManYouInProvinceRecords(CallRecord callRecord){
manYouInProvinceRecords.add(callRecord);
} public ArrayList<CallRecord> getManYouInProvinceRecords() {
return manYouInProvinceRecords;
} public ArrayList<CallRecord> getManYouOutProvinceRecords() {
return manYouOutProvinceRecords;
} public void addManYouOutProvinceRecords(CallRecord callRecord){
manYouOutProvinceRecords.add(callRecord);
} 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 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;
}
public void addSendMessageRecords(MessageRecord messageRecord){
sendMessageRecords.add(messageRecord);
}
}
class MobilePhoneCallOutCityRule extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.3;
}
return sumCost;
}
}
class MobilePhoneAnswerOutProvince extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.3;
}
return sumCost;
}
}
class MobilePhoneCallOutProvince extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.6;
}
return sumCost;
}
}
class MobilePhoneCharging extends ChargeMode{
private double monthlyRent = 15; public double calCost(UserRecords userRecords){
return 0;
}
public double getMonthlyRent(){
return monthlyRent;
}
}
class MobilePhoneInCityRule extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords
) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.1;
}
return sumCost;
}
}
class MobilePhoneInLandRule extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.3;
}
return sumCost;
}
}
class MobilePhoneInProvinceRule extends CallChargeRule{
public double calCost(ArrayList<CallRecord> callRecords) {
double sumCost=0;
long minute;
for (CallRecord callRecord:callRecords ) {
long startTime = callRecord.getStartTime().getTime();
long endTime = callRecord.getEndTime().getTime();
long second = (endTime-startTime)/1000;
if (second%60>0){
minute = second/60+1;
}
else {
minute = second/60;
}
sumCost = sumCost+minute*0.2;
}
return sumCost;
}
}

SourceMonitor的分析图如下:

分析如下:这次的计费最关键的是判断短信内容的长度,由于信息输入格式的格式为:m-主叫号码 接收号码 短信内容,而m-主叫号码 接收号码 的长度确定,可用substring方法将后面的短信内容全部截取在判断长度。

踩坑心得:主要要注意的是短信内容的格式,空格也算一个字符以及,超过10个字符的算两条,以此类推。

7-2 编写一个类Shop(商店)、内部类InnerCoupons(内部购物券)

分数 30
全屏浏览题目
切换布局
作者 吴光生
单位 新余学院

编写一个类Shop(商店),该类中有一个成员内部类InnerCoupons(内部购物券),可以用于购买该商店的牛奶(假设每箱牛奶售价为50元)。要求如下:
(1)Shop类中有私有属性milkCount(牛奶的箱数,int类型)、公有的成员方法setMilkCount( )getMilkCount( )分别用于设置和获取牛奶的箱数。
(2)成员内部类InnerCoupons,有公有属性value(面值,int类型),一个带参数的构造方法可以设定购物券的面值value,一个公有的成员方法buy( )要求输出使用了面值为多少的购物券进行支付,同时使商店牛奶的箱数减少value/50。
(3)Shop类中还有成员变量coupons50(面值为50元的内部购物券,类型为InnerCoupons)、coupons100(面值为100元的内部购物券,类型为InnerCoupons)。
(4)在Shop类的构造方法中,调用内部类InnerCoupons的带参数的构造方法分别创建上面的购物券coupons50、coupons100。

在测试类Main中,创建一个Shop类的对象myshop,从键盘输入一个整数(大于或等于3),将其设置为牛奶的箱数。假定有顾客分别使用了该商店面值为50的购物券、面值为100的购物券各消费一次,分别输出消费后商店剩下的牛奶箱数。

import java.util.Iterator; // 引入 Iterator 类import java.util.Scanner;import java.util.Collection;import java.util.ArrayList;// 1、导入相关包
//定义员工类class Employee {
    private String name;    private int age;
    public Employee() {        super();    }
    public Employee(String name, int age) {        super();        this.name = name;        this.age = age;    }
    public String getName() {        return name;    }
    public void setName(String name) {        this.name = name;    }
    public int getAge() {        return age;    }
    public void setAge(int age) {        this.age = age;    }}
//主函数public class Main {
    public static void main(String[] args) {        // 1、创建有序集合对象        Collection c = new ArrayList();
        // 创建3个员工元素对象        for (int i = 0; i < 3; i++) {            Scanner sc = new Scanner(System.in);            String employeeName = sc.nextLine();            int employeeAge = sc.nextInt();
            Employee employee = new Employee(employeeName, employeeAge);            c.add(employee);        }

        // 2、创建迭代器遍历集合        Iterator it = c.iterator();
        //3、遍历        while (it.hasNext()) {
            //4、集合中对象未知,向下转型            Employee e =  (Employee)it.next();
            System.out.println(e.getName() + "---" + e.getAge());        }    }
}

输入格式:

输入一个大于或等于3的整数。

输出格式:

使用了面值为50的购物券进行支付
牛奶还剩XX箱
使用了面值为100的购物券进行支付
牛奶还剩XX箱

输入样例:

在这里给出一组输入。例如:

5


输出样例:

在这里给出相应的输出。例如:

使用了面值为50的购物券进行支付
牛奶还剩4箱
使用了面值为100的购物券进行支付
牛奶还剩2箱
代码如下 :
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
Shop myshop=new Shop(input.nextInt());
Shop.InnerCoupons coupons50=myshop.new InnerCoupons(50);
Shop.InnerCoupons coupons100=myshop.new InnerCoupons(100);
coupons50.buy();
coupons100.buy();
}
} class Shop
{
private int milkCount;
InnerCoupons coupons50;
InnerCoupons coupons100;
public Shop(int milkCount)
{
this.milkCount=milkCount;
}
public void setMilkCount(int milkCount)
{
this.milkCount=milkCount;
}
public int getmilkCount()
{
return milkCount;
}
public class InnerCoupons
{
public int value;
public InnerCoupons(int value)
{
this.value=value;
}
public void buy()
{
Shop.this.milkCount=Shop.this.milkCount-value/50;
System.out.println("使用了面值为"+value+"的购物券进行支付");
System.out.println("牛奶还剩"+Shop.this.milkCount+"箱");
}
}
}

SourceMonitor的分析图如下:

分析如下:根据所给的代码,按照要求书写代码,只需要我们把一些细节添加上去就好了。

踩坑心得:对多态的运用

改进建议:

三、作业大总结

这次的大作业总体来说还是比之前简单很多的,但所考查知识点还是不少的,比如类之间的运用,父类与之类的合理运用,多态的使用,容器的详细使用方法和小技巧等等。这次是最后一次总结,有关于java的课程学习已经到此结束,但是,对于java的学习我觉得自己知识一个入门的水平,后序的学习还需要靠自己去掌握。回顾这一学期,在java的学习中,很多时候会被java的题目所困惑,觉得很难,跟之前学的c语言很不一样,难度突然升级。但在这个过程中学到了很多东西,练习最重要,多多练习才会让自己熟悉java。老师的讲课方式也很好,理论代码练习都有,让我们在学习的过程中,对于知识点的理解更加透彻,更容易掌握。

 
 
 
 

java pta第三次阶段性总结的更多相关文章

  1. 最新java学习路线:含阶段性java视频教程完整版

    最新java学习路线:带阶段性java视频教程版本 第一阶段:Java基础 学习目标: 掌握基本语法.面向对象.常用类.正则.集合.Io流.多线程.Nio.网络编程.JDK新特性.函数式编程 知识点细 ...

  2. Hibernate 系列 07 - Hibernate中Java对象的三种状态

    引导目录: Hibernate 系列教程 目录 1. Java对象的三种状态 当应用通过调用Hibernate API与框架发生交互时,需要从持久化的角度关注应用对象的生命周期. 持久化声明周期是Hi ...

  3. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  4. Hibernate中Java对象的三种状态

                                                                                     Hibernate中Java对象的三种 ...

  5. Java设计模式(三) 抽象工厂模式

    原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...

  6. Java进阶(三)多线程开发关键技术

    原创文章,同步发自作者个人博客,转载请务必以超链接形式在文章开头处注明出处http://www.jasongj.com/java/multi_thread/. sleep和wait到底什么区别 其实这 ...

  7. Java多线程的三种实现方式

    java多线程的三种实现方式 一.继承Thread类 二.实现Runnable接口 三.使用ExecutorService, Callable, Future 无论是通过继承Thread类还是实现Ru ...

  8. OID,主键生成策略,PO VO DTO,get和load区别,脏检查,快照,java对象的三种状态

    主键生成策略 sequence 数据库端 native 数据库端 uuid  程序端 自动赋值 生成的是一个32位的16进制数  实体类需把ID改成String 类型 assigned  程序端 需手 ...

  9. Java基础:三步学会Java Socket编程

    Java基础:三步学会Java Socket编程 http://tech.163.com 2006-04-10 09:17:18 来源: java-cn 网友评论11 条 论坛        第一步 ...

  10. java 基础知识三 java变量

    java  基础知识 三 变量 1.作用域 {} 包围起来的代码 称之为代码块,在块中声明的变量只能在块中使用 2.常量 就是固定不变的量,一旦被定义,它的值就不能再被改变. 3.变量 变量必须在程序 ...

随机推荐

  1. 阻塞I/O,非阻塞I/O,同步I/O,异步I/O

    根据应用程序是否阻塞自身运行分为: 阻塞I/O:是指应用程序在执行I/O操作后,如果没有获得响应,          就会阻塞当前线程,不能执行其他任务. 非阻塞I/O:是指应用程序在执行I/O操作后 ...

  2. [部署日记]GO在Visual Studio Code初次运行时提示go: go.mod file not found in current directory or any parent directory; see 'go help modules'

    我裂开,一波未平一波又起... 按照MS教程上填写 package main import "fmt" func main() { fmt.Println("Hello ...

  3. gitea安装部署

    安装gitea前需要先安装好git,具体参考https://www.cnblogs.com/magicMaQaQ/p/16062312.html 1.安装数据库,gitea支持多种数据库,这里选择my ...

  4. qt creator 在ubuntu22.04下显示不正常处理

    打开:sudo vim /etc/gdm3/custom.conf 找到:#WaylandEnable=false 去掉注释,问题解决

  5. CAD中如何将图形对象转换为三维实体?

    有些小伙伴在CAD绘制完图纸后,想要将图纸中的某些图形对象转换成三维实体,但却不知道该如何操作,其实很简单,本节CAD绘图教程就和小编一起来了解一下浩辰CAD软件中将符合条件的对象转换为三维实体的相关 ...

  6. CAD坐标显示不全怎么办?CAD坐标常见问题解答!

    今天小编来和大家聊一下浩辰CAD看图王中关于CAD坐标的那些事,比如:CAD坐标为何显示不全?CAD坐标显示结果和之前不一样?以及不能精准捕捉CAD坐标等情况,应该如何轻松解决?今天就和小编一起来了解 ...

  7. Python 画极坐标图

    需要用Python画极坐标等值线图,以下是所学的一些东西,特此记录 -------------------------------------------------- 翻译自 https://sta ...

  8. Jmeter性能测试入门到项目实战03

    Jmeter性能测试入门到项目实战03 P35 项目业务介绍 1,之前已经对Jmeter所有的知识点做了一个介绍,主要的业务模式是币币交易,就像b2c 2, 3, 4,主要是把登陆和交易这一块做一个并 ...

  9. java 守护线程的关闭

    在进程内所有用户线程 全部消亡后,如果 守护线程仍在执行 ( 注意: 守护线程并不是一直运行中,守护线程中的代码执行完毕,则守护线程自然消亡. ),则会被强制消亡.

  10. 利用 fastjson 的 toJSONStringWithDateFormat 方法,将Date 格式化 为常见类型的时间

    利用 fastjson 的 toJSONStringWithDateFormat 方法,将Date 格式化 为常见类型的时间 JSON.toJSONStringWithDateFormat(nrcSt ...