chengduxiu666

导航

PTA·电信计费系列问题总结

一、题目涉及的知识点

1、容器的使用

2、抛出异常

3、抽象类

4、继承与多态

5、正则表达式

二、题目分析总结

1.题目集08:7-1 电信计费系列1-座机计费

实现一个简单的电信计费程序:
假设南昌市电信分公司针对市内座机用户采用的计费方式:
月租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,可根据理解自行调整:

image.png

                                    图1
图1中User是用户类,包括属性:
userRecords (用户记录)、balance(余额)、chargeMode(计费方式)、number(号码)。

ChargeMode是计费方式的抽象类:
chargeRules是计费方式所包含的各种计费规则的集合,ChargeRule类的定义见图3。
getMonthlyRent()方法用于返回月租(monthlyRent)。

UserRecords是用户记录类,保存用户各种通话、短信的记录,    
各种计费规则将使用其中的部分或者全部记录。
其属性从上到下依次是:
市内拨打电话、省内(不含市内)拨打电话、省外拨打电话、
市内接听电话、省内(不含市内)接听电话、省外接听电话的记录
以及发送短信、接收短信的记录。
 

image.png

                                     图2
图2中CommunicationRecord是抽象的通讯记录类:
包含callingNumber拨打号码、answerNumber接听号码两个属性。
CallRecord(通话记录)、MessageRecord(短信记录)是它的子类。

CallRecord(通话记录类)包含属性:
通话的起始、结束时间以及
拨号地点的区号(callingAddressAreaCode)、接听地点的区号(answerAddressAreaCode)。
区号用于记录在哪个地点拨打和接听的电话。座机无法移动,就是本机区号,如果是手机号,则会有差异。
 

image.png

                                        图3
图3是计费规则的相关类,这些类的核心方法是:
calCost(ArrayList<CallRecord> callRecords)。
该方法针根据输入参数callRecords中的所有记录计算某用户的某一项费用;如市话费。
输入参数callRecords的约束条件:必须是某一个用户的符合计费规则要求的所有记录。

LandPhoneInCityRule、LandPhoneInProvinceRule、LandPhoneInLandRule三个类分别是
座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。    
(提示:可以从UserRecords类中获取各种类型的callRecords)。
源码如下:
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 {
        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 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 ChargeRule {
    public double calCost(ArrayList<CallRecord> callRecords){
        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;
    }
}

2.题目分析:本题是电信计费系列的第一题,也是相对后面两题难度最大的一题,因为需要根据所给的类图构建本系列题目的大体框架,后续题目再在框架上继续延伸扩展,设计难度和代码量较大。

本题需要注意的有以下几个点:

1.输入格式的正则表达式,要注意日期的合法性。

2.根据题目要求,忽略重复开户的操作。

3.具体实现思路:

创建一个可储存用户的容器,判断输入的信息,如果判断为开户信息,再判断容器中是否存在相同的账户号码,不存在则在容器中添加该用户,如果判断为通话信息,在判断拨打号码和收听号码是否是容器中的号码,若是则将

拨打(收听)信息存入用户中的储存相应信息的容器中。最后的计费则是将用户里的每条拨打信息的时间提取出来进行计算即可。

4.遇到的bug

因为座机计费规则还是比较简单,并且只有座机与座机的通话所以没有遇到很大的bug,只遇到了将通讯时间计算错误,以及日期的正则表达式错误两个较小的bug。

 

2.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:

image.png
图1

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

image.png

图2

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

image.png
图3

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

源码如下:

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 {
        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);

        MobilePhoneInCityRule mobilePhoneInCityRule = new MobilePhoneInCityRule();
        MobilePhoneInProvinceRule mobilePhoneInProvinceRule = new MobilePhoneInProvinceRule();
        MobilePhoneInLandRule mobilePhoneInLandRule = new MobilePhoneInLandRule();
        MobilePhoneCallOutCityRule mobilePhoneCallOutCityRule = new MobilePhoneCallOutCityRule();
        MobilePhoneCallOutProvince mobilePhoneCallOutProvince = new MobilePhoneCallOutProvince();
        MobilePhoneAnswerOutProvince mobilePhoneAnswerOutProvince = new MobilePhoneAnswerOutProvince();

        MobilePhoneCharging mobilePhoneCharging = new MobilePhoneCharging();
        mobilePhoneCharging.getChargeRules1().add(mobilePhoneInCityRule);
        mobilePhoneCharging.getChargeRules1().add(mobilePhoneInProvinceRule);
        mobilePhoneCharging.getChargeRules1().add(mobilePhoneInLandRule);
        mobilePhoneCharging.getChargeRules1().add(mobilePhoneCallOutCityRule);
        mobilePhoneCharging.getChargeRules1().add(mobilePhoneCallOutProvince);
        mobilePhoneCharging.getChargeRules1().add(mobilePhoneAnswerOutProvince);

        ArrayList<User> UserList = new ArrayList<>();
        ArrayList<User> User1List = new ArrayList<>();
        Scanner in = new Scanner(System.in);
        String m = in.nextLine();
        int flag;
        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()) {
                    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.isUser1Information(m)) {
                String regex = "[\\d][\\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.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();
                }
            }
            if (judge.isCalling01Information(m)) {
                String[] a = m.split(" ");
                try {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                    Date startTime = format.parse(a[3] + " " + a[4]);
                    Date endTime = format.parse(a[5] + " " + a[6]);
                    for (User user : UserList
                    ) {
                        if (user.getNumber().equals(a[0].substring(2))) {
                            if (judge.isInCityCode(a[2])) {
                                user.getUserRecords().addCallingInCityRecords(new CallRecord(startTime, endTime, a[0].substring(2, 6), a[2]));
                            } else if (judge.isInProvinceCode(a[2])) {
                                user.getUserRecords().addCallingInProvinceRecords(new CallRecord(startTime, endTime, a[0].substring(2, 6), a[2]));
                            } else {
                                user.getUserRecords().addCallingInLandRecords(new CallRecord(startTime, endTime, a[0].substring(2, 6), a[2]));
                            }
                        }
                    }
                    for (User user : User1List
                    ) {
                        if (user.getNumber().equals(a[1])) {
                            if (judge.isAnswerInCityCode1(a[2])) {
                                ;
                            } else if (judge.isAnswerInProvinceCode1(a[2])) {
                                ;
                            } else {
                                user.getUserRecords().addAnswerInLandRecords(new CallRecord(startTime, endTime, a[0].substring(2, 6), a[2]));
                            }
                        }
                    }

                } catch (ParseException e) {
                    e.printStackTrace();
                }

            }
            if (judge.isCalling11Information(m)) {
                String[] a = m.split(" ");
                try {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                    Date startTime = format.parse(a[4] + " " + a[5]);
                    Date endTime = format.parse(a[6] + " " + a[7]);
                    for (User user : User1List
                    ) {
                        if (user.getNumber().equals(a[0].substring(2))) {
                            if (judge.isCallInCity(a[1])) {
                                if (judge.isInCityCode(a[3])) {
                                    user.getUserRecords().addCallingInCityRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                                } else if (judge.isInProvinceCode(a[3])) {
                                   user.getUserRecords().addCallingInProvinceRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                                } else {
                                    user.getUserRecords().addCallingInLandRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                                }
                            } else if (judge.isInProvinceCode(a[1])) {
                                user.getUserRecords().addManYouInProvinceRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                            } else {
                                user.getUserRecords().addManYouOutProvinceRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                            }
                        }
                    }
                    for (User user : User1List
                    ) {
                        if (user.getNumber().equals(a[2])) {
                            if (judge.isAnswerInCityCode1(a[3])) {
                                ;
                            } else if (judge.isAnswerInProvinceCode1(a[3])) {
                                ;
                            } else {
                                user.getUserRecords().addAnswerInLandRecords(new CallRecord(startTime, endTime, a[0].substring(2, 6), a[2]));
                            }
                        }
                    }

                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
                      if (judge.isCalling10Information(m)) {
                String[] a = m.split(" ");
                try {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                    Date startTime = format.parse(a[3] + " " + a[4]);
                    Date endTime = format.parse(a[5] + " " + a[6]);
                    for (User user : User1List
                    ) {
                        if (user.getNumber().equals(a[0].substring(2))) {
                            if (judge.isCallInCity(a[1])) {
                                if (judge.isInCityCode(a[2].substring(0,4))) {
                                    user.getUserRecords().addCallingInCityRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                                } else if (judge.isInProvinceCode(a[2].substring(0,4))) {
                                    user.getUserRecords().addCallingInProvinceRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                                } else {
                                    user.getUserRecords().addCallingInLandRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                                }
                            } else if (judge.isInProvinceCode(a[1])) {
                                user.getUserRecords().addManYouInProvinceRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                            } else {
                                user.getUserRecords().addManYouOutProvinceRecords(new CallRecord(startTime, endTime, a[1], a[3]));
                            }
                        }
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            m = in.nextLine();
        }
            for (User user : UserList
            ) {
                user.setChargeMode(landlinePhoneCharging);
            }
            for (User user:User1List
                 ) {
                user.setChargeMode(mobilePhoneCharging);
            }
            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 (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 : UserList
            ) {
                System.out.printf("%s %.1f %.1f\n", user.getNumber(), user.getChargeMode().calCost(user.getUserRecords()), user.getBalance());
            }
            for (User user : User1List
            ) {
                System.out.printf("%s %.1f %.1f\n", user.getNumber(), user.getChargeMode().calCost(user.getUserRecords()), user.getBalance());
            }
    }
}
 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<>();
     private ArrayList<ChargeRule> chargeRules1 = new ArrayList<>();

    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 {
    public double calCost(ArrayList<CallRecord> callRecords){
        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 isUser1Information(String s){
        String pattern = "(u-)[1][\\d]{10}[\\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 isCalling01Information(String s){
        String pattern = "[t]-0[0-9]{9,11}\\s" + "[1][\\d]{10}\\s"+"[\\d]{3,4}\\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 isCalling11Information(String s){
        String pattern = "(t-)[1][\\d]{10}\\s"+"[\\d]{3,4}\\s" + "[1][\\d]{10}\\s"+"[\\d]{3,4}\\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 isCalling10Information(String s){
        String pattern = "(t-)[1][\\d]{10}\\s"+"[\\d]{3,4}\\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);
    }
    public boolean isAnswerInCityCode1(String s){
        String pattern = "0791";
        return s.equals(pattern);
    }
    public boolean isAnswerInProvinceCode1(String s){
        String pattern = "((0790)|(0701)|((079)[2-9]))";
        return  s.matches(pattern);
    }
    public boolean isCallInCity(String s){
        String pattern = "0791";
        return s.equals(pattern);
    }
    public boolean isCallInProvince(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<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;
}
}
    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){
        double sum=0;
        sum = getChargeRules1().get(0).calCost(userRecords.getCallingInCityRecords())+getChargeRules1().get(1).calCost(userRecords.getCallingInProvinceRecords())+getChargeRules1().get(2).calCost(userRecords.getCallingInLandRecords())+getChargeRules1().get(3).calCost(userRecords.getManYouInProvinceRecords())+getChargeRules1().get(4).calCost(userRecords.getManYouOutProvinceRecords())+getChargeRules1().get(5).calCost(userRecords.getAnswerInLandRecords());;
        return sum;
    }
    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;
    }
}

1.题目分析:本题的计费形式对于上一题多了很多种,主要是手机的计费规则多了省内漫游和省外漫游。

本题需要注意以下几点:

1.手机计费根据哪套规则记录费用不是按照开户时的地址进行计算,而是根据拨打人拨打时所在的区号以及接听人接听所在区号进行计费。

实现思路:在上题的基础上,增加储存手机用户的容器,增加相应手机计费规则,以及判断手机通讯信息的正则表达式,储存手机用户的方式和上题储存座机用户的方式基本一致,根据拨打人所在区号根据接听人的区号判断是市内省内还是国内长途信息等类型,在用户信息里建立对应的容器储存它们。

3.遇到的bug

这道题遇到bug的原因大多是在计费方面,由于存在座机打手机,手机打手机,手机打座机等,所以在数据储存时,他们的信息格式各不相同,出现了一些信息储存错误的小bug。

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

其他题目信息与上题相同,主要多了以下内容:

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

3、逐行输入本月某些用户的短信信息,短信的格式:
m-主叫号码,接收号码,短信内容 (短信内容只能由数字、字母、空格、英文逗号、英文句号组成)
m-18907910010 13305862264 welcome to jiangxi.
m-13305862264 18907910010 thank you.

源码如下:

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;
    }
}

1.题目分析:题目要求很明确,主要要注意的是短信内容的格式,空格也算一个字符以及,超过10个字符的算两条,以此类推。

 2.具体实现思路:本题最关键的是判断短信内容的长度,由于信息输入格式的格式为:m-主叫号码 接收号码 短信内容,而m-主叫号码 接收号码 的长度确定,可用substring方法将后面的短信内容全部截取在判断长度。
3.遇到的bug:无。
三、总结:对于这次题目集我最大的收获是认识到了一个合理的设计的重要性,由于代码是基于第一次题目集所给的类图上设计的,对于后面的题目集所做出的功能拓展我不需要改变太多代码就能实现功能,如果让我设计的话,估计每次题目集都要将代码进行大幅度修改才能实现相应功能。
 

 

posted on 2022-06-16 16:19  呈独秀  阅读(356)  评论(0编辑  收藏  举报