首页 > 其他分享 >第三次博客

第三次博客

时间:2022-12-10 21:34:18浏览次数:61  
标签:return String double ArrayList 博客 new public 第三次

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,可根据理解自行调整:

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)。
 

后续扩展说明:
后续题目集将增加手机用户,手机用户的计费方式中除了与座机计费类似的主叫通话费之外,还包含市外接听电话的漫游费以及发短信的费用。在本题的设计时可统一考虑。
通话记录中,手机需要额外记录拨打/接听的地点的区号,比如:
座机打手机: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.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        ArrayList<User> us = new ArrayList<User>();
        DecimalFormat x1 = new DecimalFormat("###.0#");
        ArrayList<CallRecord> callRecords = new ArrayList<CallRecord>();
        while(true)
        {
            String[] arry = null;
            Date starttime=null;
            Date endtime=null;
            String n=in.nextLine();
            if(n.equals("end")) {
                break;}
            if(n.matches("u-079[\\d]{1}[\\d]{7,9} 0")||n.matches("u-0701[\\d]{7,9} 0")||n.matches("t-[\\d]{11,12}\\s[\\d]{11,12}\\s[\\d]{4}.[1-12].[1-31]\\s([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]\\s[\\d]{4}.[1-12].[1-31]\\s([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]"))
            {
                arry=n.split("-| ");
                if(arry[0].equals("t")) {
                    CallRecord callRecord = new CallRecord();
                    String answerareaCode,callareaCode;//接听区号;拨打区号
                    callareaCode = arry[1].substring(0, 4);//赋值
                    answerareaCode = arry[2].substring(0, 4);//赋值
                    callRecord.setCallingAddressAreaCode(callareaCode);
                    callRecord.setAnswerAddressAreaCode(answerareaCode);
                    callRecord.setCallingNumber(arry[1]);
                    callRecord.setAnswerNumber(arry[2]);
                    SimpleDateFormat time = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                    try {
                        starttime = time.parse(arry[3]+" "+arry[4]);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    try {
                        endtime = time.parse(arry[5]+" "+arry[6]);
                    } catch (ParseException e1) {
                        e1.printStackTrace();
                    }
                    callRecord.setStartTime(starttime);//开始时间
                    callRecord.setEndTime(endtime);//结束时间
                    callRecords.add(callRecord);//添加用户记录
                }
                if(arry[0].equals("u")){
                    String areaCode;
                    CallRecord callRecord = new CallRecord();
                    LandlinePhoneCharging lip = new LandlinePhoneCharging();//座机
                    boolean decide = true;
                    areaCode = arry[1].substring(0, 4);
                    callRecord.setCallingAddressAreaCode(areaCode);
                    for(User user : us)
                    {
                        if(user.getNumber().equals(arry[1]))
                            decide=false;
                    }
                    if(decide==true) {
                        User u = new User(lip,arry[1]);
                        us.add(u);
                    }
                }
            }
        }
        for(int i=0;i<us.size();i++) {
            UserRecords u=new UserRecords();
            for(int j=0;j<callRecords.size();j++) {
                CallRecord a=callRecords.get(j);
                String callnumber=a.callnumber;
                if(us.get(i).number.equals(callnumber)) {
                    if(a.getAnswerAddressAreaCode().matches("0791"))u.addCallingInCityRecords(a);
                    else if(a.getAnswerAddressAreaCode().matches("0701"))u.addCallingInProvinceRecords(a);
                    else if(a.getAnswerAddressAreaCode().matches("079[0-9]"))u.addCallingInProvinceRecords(a);
                    else u.addCallingInLandRecords(a);
                }
            }
            us.get(i).setUserRecords(u);
        }
        Collections.sort(us,new Comparator<User>() {
            public int compare(User o1, User o2) {
                // TODO Auto-generated method stub
                double x=Double.parseDouble(o1.getNumber());
                double y=Double.parseDouble(o2.getNumber());
                return (int) (x-y);
            }
        });
        for(User u : us) {
            double cost=Double.parseDouble(x1.format(u.calCost()));
            double balance=Double.parseDouble(x1.format(u.calBalance()));
            System.out.println(u.getNumber()+" "+cost+" "+balance);
        }
        in.close();
    }
}

class User {
    UserRecords userRecords = new UserRecords();
    double balance = 100;
    ChargeMode chargeMode;
    String number;
    User(ChargeMode chargeMode,String number){
        this.chargeMode=chargeMode;
        this.number=number;
    }
    double calBalance() {
        double a = balance-(calCost()+chargeMode.getMonthlyRent());
        return a;
    }
    double calCost() {
        double s =chargeMode.calCost(userRecords);
        return s;
    }
    UserRecords getUserRecords() {
        return userRecords;
    }
    void setUserRecords(UserRecords userRecords) {
        this.userRecords=userRecords;
    }
    double getBalance() {
        return balance;
    }
    ChargeMode getChargeMode() {
        return chargeMode;
    }
    void setChargeMode(ChargeMode chargeMode) {
        this.chargeMode = chargeMode;
    }
    String getNumber() {
        return number;
    }
    void setNumber(String number) {
        this.number = number;
    }
}
class UserRecords {
    ArrayList<CallRecord>callinglnCityRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord>callinglnProvinceRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord>callinglnLandRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord>answerlnCityRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord>answerlnProvinceRecords = new ArrayList<CallRecord>();
    ArrayList<CallRecord>answerlnLandRecords = new ArrayList<CallRecord>();
    ArrayList<MessageRecord>sendMessageRecords = new ArrayList<MessageRecord>();
    ArrayList<MessageRecord>receiveMessageRecords = new ArrayList<MessageRecord>();
    public void addCallingInCityRecords (CallRecord callRecord) {
        callinglnCityRecords.add(callRecord);
    }
    public void addCallingInProvinceRecords (CallRecord callRecord) {
        callinglnProvinceRecords.add(callRecord);
    }
    public void addCallingInLandRecords (CallRecord callRecord) {
        callinglnLandRecords.add(callRecord);
    }
    public void addAnswerInCityRecords (CallRecord answerRecord) {
        answerlnCityRecords.add(answerRecord);
    }
    public void addAnswerInProvinceRecords (CallRecord answerRecord) {
        answerlnProvinceRecords.add(answerRecord);
    }
    public void addAnswerInLandRecords (CallRecord answerRecord) {
        answerlnLandRecords.add(answerRecord);
    }

    public void addSendMessageRecords (MessageRecord sendMessageRecord) {
        sendMessageRecords.add(sendMessageRecord);
    }
    public void addReceiveMessageRecords (MessageRecord receiveMessageRecord) {
        receiveMessageRecords.add(receiveMessageRecord);
    }
    public ArrayList<MessageRecord> getSendMessageRecords (){
        return this.sendMessageRecords;
    }
    public ArrayList<MessageRecord> getReceiveMessageRecords (){
        return this.receiveMessageRecords;
    }
    public ArrayList<CallRecord> getCallingInCityRecords (){
        return this.callinglnCityRecords;
    }
    public ArrayList<CallRecord> getCallingInProvinceRecords (){
        return this.callinglnProvinceRecords;
    }
    public ArrayList<CallRecord> getCallingInLandRecords (){
        return this.callinglnLandRecords;
    }
    public ArrayList<CallRecord> getAnswerInCityRecords (){
        return this.answerlnCityRecords;
    }
    public ArrayList<CallRecord> getAnswerInProvinceRecords (){
        return this.callinglnProvinceRecords;
    }
    public ArrayList<CallRecord> getAnswerInLandRecords (){
        return this.callinglnLandRecords;
    }
}

abstract class   ChargeMode {
    private ArrayList<ChargeRule> chargeRules= new ArrayList<>();
    public ArrayList<ChargeRule> getChargeRule(){
        return chargeRules;
    }
    public  void setChargeRules(ArrayList<ChargeRule> chargeRules) {
        this.chargeRules= chargeRules;
    }
    public abstract double calCost(UserRecords userRecords);
    abstract double getMonthlyRent() ;

}

class LandlinePhoneCharging extends ChargeMode   {
    double monthlyRent = 20;
    public double calCost(UserRecords userRecords) {
        double sum = 0.0;
        LandPhoneInlandRule p1 = new LandPhoneInlandRule();
        LandPhonelnCityRule p2 = new LandPhonelnCityRule();
        LandPhonelnProvinceRule p3 = new LandPhonelnProvinceRule();
        double sum1= sum+p1.calCost(userRecords.getCallingInLandRecords());
        double sum2=sum+p2.calCost(userRecords.getCallingInCityRecords());
        double sum3=sum+p3.calCost(userRecords.getCallingInProvinceRecords());
        return sum1+sum2+sum3;
    }
    public double getMonthlyRent() {
        return monthlyRent;
    }
}

abstract class CommunicationRecord {
    private String callingNumber;
    private String answerNumber;
    public String getCallingNumber() {
        return callingNumber;
    }
    public void setCallingNumber(String callingNumber) {
        this.callingNumber=callingNumber;
    }
    public String getAnswerNumber() {
        return answerNumber;
    }
    public void setAnswerNumber(String answerNumber) {
        this.answerNumber=answerNumber;
    }
}

class CallRecord extends CommunicationRecord{
    Date startTime;
    Date endTime;
    String callingAddressAreaCode;
    String answerAddressAreaCode;
    String callnumber;
    String answernumber;
    Date getStartTime() {
        return startTime;
    }
    void setStartTime(Date starttime2) {
        this.startTime=(Date) starttime2;
    }
    Date getEndTIme() {
        return endTime;
    }
    void setEndTime(Date endtime2) {
        this.endTime=(Date) endtime2;
    }
    String getCallingAddressAreaCode() {
        return callingAddressAreaCode;
    }
    void setCallingAddressAreaCode(String callingAddressAreaCode) {
        this.callingAddressAreaCode=callingAddressAreaCode;
    }
    String getAnswerAddressAreaCode() {
        return answerAddressAreaCode;
    }
    void setAnswerAddressAreaCode(String answerAddressAreaCode) {
        this.answerAddressAreaCode=answerAddressAreaCode;
    }
    public void setCallingNumber(String string) {
        this.callnumber=string;
    }
    public void setAnswerNumber(String string) {
        this.answernumber=string;
    }
}

class MessageRecord extends CommunicationRecord {
    String message;
    String getMessage() {
        return message;
    }
    void setMessage(String message) {
        this.message=message;
    }
}

abstract class ChargeRule {

}

abstract class CallChargeRule extends ChargeRule {
    public abstract double calCost(ArrayList<CallRecord>callRecords);

}

class LandPhoneInlandRule extends CallChargeRule{
    public double calCost(ArrayList<CallRecord> callRecords) {
        double sum=0.0;
        for(int i=0;i<callRecords.size();i++)
        {
            double s = callRecords.get(i).getEndTIme().getTime()-callRecords.get(i).getStartTime().getTime();
            s=s/1000.0/60;//分钟
            if(s%1==0) {
                sum+=s*0.6;
            }
            else {
                double a=s%1;
                s=s-a+1;
                sum+=s*0.6;
            }
        }
        return sum;
    }
}

class LandPhonelnCityRule extends CallChargeRule {
    public double calCost(ArrayList<CallRecord> callRecords) {
        double sum=0;
        for(int i=0;i<callRecords.size();i++)
        {
            double s = callRecords.get(i).getEndTIme().getTime()-callRecords.get(i).getStartTime().getTime();
            s=s/1000.0/60;//分钟
            if(s%1==0) {
                sum+=s*0.1;
            }
            else {
                double a=s%1;
                s=s-a+1;
                sum+=s*0.1;
            }
        }
        return sum;
    }
}

class LandPhonelnProvinceRule extends CallChargeRule{
    public double calCost(ArrayList<CallRecord> callRecords) {
        double sum=0;
        for(int i=0;i<callRecords.size();i++)
        {
            double s = callRecords.get(i).getEndTIme().getTime()-callRecords.get(i).getStartTime().getTime();
            s=s/1000.0/60;//分钟
            if(s%1==0) {
                sum+=s*0.3;
            }
            else {
                double a=s%1;
                s=s-a+1;
                sum+=s*0.3;
            }
        }
        return sum;
    }
}

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:

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三个类分别是座机拨打市内、省内、省外电话的计费规则类,用于实现这三种情况的费用计算。    
 

(提示:可以从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
 

更多内容详见附件:

电信计费简化版-座机计费说明.pdf


源代码展示:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class Main{
    public static void main(String[] args) throws ParseException {
        Scanner input = new Scanner(System.in);
        ArrayList<User> users = new ArrayList<User>();
        String string = input.nextLine();
        String datePatten = "((([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])\\.(" +
                "[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])";
        String patten1 = "[u][-][0][7][9][1][0-9]{7,8}\\s[0]";
        String patten2 = "[u][-][1][3][0-9]{9}\\s[1]";

        String patten3 = "[t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s"+datePatten + "\\s" + datePatten;//座机打座机
        String patten4 = "[t]-0791[0-9]{7,8}\\s" +"1[0-9]{10}\\s"+"0[0-9]{2,3}\\s"+datePatten + "\\s" + datePatten;//座机打手机
        String patten5 = "[t]-1[0-9]{10}\\s" +"0[0-9]{2,3}\\s"+"0[0-9]{10,11}\\s"+datePatten + "\\s" + datePatten;//手机打座机
        String patten6 = "[t]-1[0-9]{10}\\s" +"0[0-9]{2,3}\\s"+"1[0-9]{10}\\s"+"0[0-9]{2,3}\\s"+datePatten + "\\s" + datePatten;//手机打手机

        while (!string.equals("end")) {
            String str[] = string.split(" ");
            if (string.matches(patten1)) {
                String number = str[0].substring(2);
                if (!isUser(number,users)) {
                    User user = new User(number);
                    LandlinePhoneCharging landlinePhoneCharging = new LandlinePhoneCharging();
                    user.setChargeMode(landlinePhoneCharging);
                    users.add(user);
                }
            }else if (string.matches(patten2)) {
                String number = str[0].substring(2);
                if (!isUser(number,users)) {
                    User user = new User(number);
                    MobilelinePhoneCharing mobilePhoneCharging = new  MobilelinePhoneCharing();
                    user.setChargeMode(mobilePhoneCharging);
                    users.add(user);
                }
            }else if (string.matches(patten3)) {
                Date startTime = new Date();
                Date endTime = new Date();
                String callNum = str[0].substring(2);
                String answerNum = str[1];
                SimpleDateFormat content = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                startTime = content.parse(str[2] + " " + str[3]);
                endTime = content.parse(str[4] + " "+ str[5]);
                CallRecord callRecord = new CallRecord(startTime,endTime,callNum,answerNum);
                setLinePhoneCallRecord(users,callNum,answerNum,callRecord);

            }else if (string.matches(patten4)) { //座机打手机
                Date startTime = new Date();
                Date endTime = new Date();
                String callNum = str[0].substring(2);
                String answerNum = str[1];
                SimpleDateFormat content = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                startTime = content.parse(str[3] + " " + str[4]);
                endTime = content.parse(str[5] + " " + str[6]);
                CallRecord callRecord = new CallRecord(startTime,endTime,callNum,answerNum);
                if (isUser(callNum,users)) {
                    int n = findUserNum(callNum,users);
                    int check = checkLinePhone(str[2]);
                    if (check == 1) {
                        users.get(n).getUserRecords().addCallingInCityRecords(callRecord);
                    }else if (check == 2) {
                        users.get(n).getUserRecords().addCallingInProvinceRecords(callRecord);
                    }else if (check == 3) {
                        users.get(n).getUserRecords().addCallingInLandRecords(callRecord);
                    }
                }
                if (isUser(answerNum,users)){
                    int n = findUserNum(answerNum,users);
                    int check = checkLineToMobile(callNum,str[2]);
                    if (!callNum.substring(0,4).matches("[0][7]([9][0-9]|[0][1])") || !str[2].matches("[0][7]([9][0-9]|[0][1])")) {
                        users.get(n).getUserRecords().addAnswerOutProvinceRecords(callRecord);
                    }
                }
            }else if (string.matches(patten5)) { //手机打座机
                Date startTime = new Date();
                Date endTime = new Date();
                String callNum = str[0].substring(2);
                String answerNum = str[2];
                SimpleDateFormat content = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                startTime = content.parse(str[3] + " " + str[4]);
                endTime = content.parse(str[5] + " " + str[6]);
                CallRecord callRecord = new CallRecord(startTime,endTime,callNum,answerNum);
                if (isUser(callNum,users)) {
                    int n = findUserNum(callNum,users);
                    int check = checkMobileToLine(str[1],answerNum.substring(0,4));
                    switch (check) {
                        case 1:
                            users.get(n).getUserRecords().addCallingInCityRecords(callRecord);break;
                        case 2:
                            users.get(n).getUserRecords().addCallingInProvinceRecords(callRecord);break;
                        case 3:
                            users.get(n).getUserRecords().addCallingInLandRecords(callRecord);break;
                        case 4:
                            users.get(n).getUserRecords().addCallingRecordsInProvince(callRecord);break;
                        case 5:
                            users.get(n).getUserRecords().addCallingOutProvinceRecords(callRecord);break;
                    }
                }
            }else if (string.matches(patten6)) { //手机互打
                Date startTime = new Date();
                Date endTime = new Date();
                String callNum = str[0].substring(2);
                String answerNum = str[2];
                SimpleDateFormat content = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
                startTime = content.parse(str[4] + " " + str[5]);
                endTime = content.parse(str[6] + " " + str[7]);
                CallRecord callRecord = new CallRecord(startTime,endTime,callNum,answerNum);
                setMobilePhoneCallRecord(users,callNum,answerNum,callRecord,str[1],str[3]);
            }
            string = input.nextLine();
        }
        Collections.sort(users, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getNumber().compareTo(o2.getNumber());
            }
        });
        for (int i = 0;i < users.size();i++) {
            System.out.println(String.format("%s %.1f %.1f",users.get(i).getNumber(),users.get(i).calCost(),
                    users.get(i).calBalance()));
        }
    }

    public static long calDiffFormTwoDate(Date date1,Date date2) {
        long startTime = date1.getTime();
        long endTime = date2.getTime();
        long minutes = (int)Math.ceil((endTime - startTime) / 1000.0 / 60);
        return minutes;
    }

    public static boolean isUser(String number,ArrayList<User> users) {
        for (int i = 0;i < users.size();i++) {
            if (number.equals(users.get(i).getNumber())) {
                return true;
            }
        }
        return false;
    }
    public static int findUserNum(String number,ArrayList<User> users) {
        for (int i = 0;i < users.size();i++) {
            if (number.equals(users.get(i).getNumber())) {
                return i;
            }
        }
        return 0;
    }
    public static int checkLinePhone(String number) {
        if (number.matches("[0][7][9][1]")) {
            return 1;
        }else if (number.matches("[0][7]([9][0|2-9]|[0][1])")) {
            return 2;
        }else {
            return 3;
        }
    }
    public static int checkLineToMobile(String s1,String s2) {
        if (s1.substring(0,5).matches(s2)) {
            return 1;
        }else if (s2.equals("079")) {
            return 2;
        }else {
            return 3;
        }
    }
    public static void setLinePhoneCallRecord(ArrayList<User> users,String number,String answer,CallRecord callRecord) {
        if (isUser(number,users)) {
            int n = findUserNum(number,users);
            int check = checkLinePhone(answer.substring(0,4));
            if (check == 1) {
                users.get(n).getUserRecords().addCallingInCityRecords(callRecord);
            }else if (check == 2) {
                users.get(n).getUserRecords().addCallingInProvinceRecords(callRecord);
            }else if (check == 3) {
                users.get(n).getUserRecords().addCallingInLandRecords(callRecord);
            }
        }
    }
    public static int checkMobileToLine(String s1,String s2) {
        if (s1.equals("0791")) {
           if (s2.equals("0791")) {
               return 1;
           }else if (s2.matches("[0][7]([9][0|2-9]|[0][1])")) {
               return 2;
           }else {
               return 3;
           }
        }else {
            if (s1.matches("[0][7]([9][0|2-9]|[0][1])")) {
                return 4;
            }else {
                return 5;
            }
        }
    }
    public static void setMobilePhoneCallRecord(ArrayList<User> users,String call,String answer,CallRecord callRecord,String s1,String s2) {
        if (isUser(call,users)) {     //主叫记录存储                  //手机互打时的记录存储
            int n = findUserNum(call,users);
            int check = checkMobileToLine(s1,s2);
            switch (check) {
                case 1:
                    users.get(n).getUserRecords().addCallingInCityRecords(callRecord);break;
                case 2:
                    users.get(n).getUserRecords().addCallingInProvinceRecords(callRecord);break;
                case 3:
                    users.get(n).getUserRecords().addCallingInLandRecords(callRecord);break;
                case 4:
                    users.get(n).getUserRecords().addCallingRecordsInProvince(callRecord);break;
                case 5:
                    users.get(n).getUserRecords().addCallingOutProvinceRecords(callRecord);break;
            }
        }
        if (isUser(answer,users)) { //接听记录存储,只存省外漫游
            int n  = findUserNum(answer,users);
            int check = checkMobileToLine(s2,s1);
            if (check == 5){
                users.get(n).getUserRecords().addAnswerOutProvinceRecords(callRecord);
            }
        }
    }

}




abstract class CallChargeRule extends ChargeRule{
    public abstract double calCost(ArrayList<CallRecord> callRecords);
}
class CallRecord extends CommunicationRecord{
    Date startTime;
    Date endTime;
    String callingAddressAreaCode;
    String answerAddressAreaCode;
    public Date getStartTime() {
        return startTime;
    }
    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }
    public Date getEndTime() {
        return endTime;
    }
    public CallRecord(Date startTime, Date endTime, String callingAddressAreaCode, String anserAddressAreaCode) {
        super();
        this.startTime = startTime;
        this.endTime = endTime;
        this.callingAddressAreaCode = callingAddressAreaCode;
        this.answerAddressAreaCode = anserAddressAreaCode;
    }
    public void setEndTime(Date endTime) {
        this.endTime = endTime;
    }
    public String getCallingAddressAreaCode() {
        return callingAddressAreaCode;
    }
    public void setCallingAddressAreaCode(String callingAddressAreaCode) {
        this.callingAddressAreaCode = callingAddressAreaCode;
    }
    public String getAnserAddressAreaCode() {
        return answerAddressAreaCode;
    }
    public void setAnserAddressAreaCode(String anserAddressAreaCode) {
        this.answerAddressAreaCode = anserAddressAreaCode;
    }
    
}
abstract class ChargeMode {
    ArrayList<ChargeRule> chargeRules = new ArrayList<ChargeRule>();
    public ArrayList<ChargeRule> getChargeRules() {
        return chargeRules;
    }
    public void setChargeRules(ArrayList<ChargeRule> chargeRules) {
        this.chargeRules = chargeRules;
    }
    public abstract double calCost(UserRecords userRecords);
    public abstract double getMonthlyRent();
}
abstract class ChargeRule {

}
abstract class CommunicationRecord {
    protected String callingNumber;
    protected String anserNumber;
    public String getCallingNumber() {
        return callingNumber;
    }
    public void setCallingNumber(String callingNumber) {
        this.callingNumber = callingNumber;
    }
    public String getAnserNumber() {
        return anserNumber;
    }
    public void setAnserNumber(String anserNumber) {
        this.anserNumber = anserNumber;
    }
    
    
}
class LandlinePhoneCharging extends ChargeMode {
    private double monthlyRent = 20;
    LandPhoneInCityRule landCity = new LandPhoneInCityRule();
    LandPhoneInLandRule landLand = new LandPhoneInLandRule();
    LandPhoneInProvinceRule landProvince = new LandPhoneInProvinceRule();
    @Override
    public double calCost(UserRecords userRecords) {
        // TODO Auto-generated method stub
        double cost =0;
        cost = cost+landCity.calCost(userRecords.getCallingInCityRecords())+landLand.calCost(userRecords.getCallingInLandRecords())+landProvince.calCost(userRecords.getCallingInProvinceRecords());
//        System.out.println(cost);
        return cost;
    }
    @Override
    public double getMonthlyRent() {
        // TODO Auto-generated method stub
        return monthlyRent;
    }
    
}
class LandPhoneInCityRule extends CallChargeRule{

    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.1 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.1 * time;
            }
        }
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
//        System.out.println(cost2);
        return cost2;
    }
    
}
class LandPhoneInLandRule extends CallChargeRule{

    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        // TODO Auto-generated method stub
        int time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.6 * time;    
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.6 * time;    
            }
        }        
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
        return cost2;
    }
    

}
class LandPhoneInProvinceRule extends CallChargeRule{

    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.3 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.3 * time;
            }
        }    
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
        return cost2;
    }
    

}
abstract class MessageChargeRule extends ChargeRule{
    public abstract double calCost(ArrayList<MessageRecord> messageRecords);
}
class MessageRecord extends CommunicationRecord{
    String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    

}
class MobilelinePhoneCharing extends ChargeMode {
    private double monthlyRent = 15;
    MobilePhoneInCityRule mobileCity = new MobilePhoneInCityRule();
    MobilePhoneInLandRule mobileLand = new MobilePhoneInLandRule();
    MobilePhoneInProvinceRule mobileProvince = new MobilePhoneInProvinceRule();
    MobilePhoneCallInProvinceRule mobileCallInProvince = new MobilePhoneCallInProvinceRule();
    MobilePhoneCallOutProvinceRule mobileCallOutProvince = new MobilePhoneCallOutProvinceRule();
    MobilePhoneAnswerOutProvinceRule mobileAnswerOutProvince = new MobilePhoneAnswerOutProvinceRule();
    
    @Override
    public double calCost(UserRecords userRecords) {
        // TODO Auto-generated method stub
        double cost =0;
        cost = cost+mobileCity.calCost(userRecords.getCallingInCityRecords())+mobileLand.calCost(userRecords.getCallingInLandRecords())+mobileProvince.calCost(userRecords.getCallingInProvinceRecords());
//        System.out.println(cost);
        cost = cost+mobileCallInProvince.calCost(userRecords.getCallingRecordsInProvince())+mobileAnswerOutProvince.calCost(userRecords.getAnswerOutProvinceRecords())+mobileCallOutProvince.calCost(userRecords.getCallingOutProvinceRecords());
        return cost;
    }
    @Override
    public double getMonthlyRent() {
        // TODO Auto-generated method stub
        return monthlyRent;
    }
    
}
class MobilePhoneAnswerOutProvinceRule extends CallChargeRule{
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.3 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.3 * time;
            }
        }
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
//        System.out.println(cost2);
        return cost2;
    }
}
class MobilePhoneCallInProvinceRule extends CallChargeRule{
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.3 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.3 * time;
            }
        }
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
//        System.out.println(cost2);
        return cost2;
    }
}
class MobilePhoneCallOutProvinceRule extends CallChargeRule{
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.6 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.6 * time;
            }
        }
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
//        System.out.println(cost2);
        return cost2;
    }
}
class MobilePhoneInCityRule  extends CallChargeRule{

    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.1 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.1 * time;
            }
        }
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
//        System.out.println(cost2);
        return cost2;
    }
    
}
class MobilePhoneInLandRule  extends CallChargeRule{
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.3 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.3 * time;
            }
        }
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
//        System.out.println(cost2);
        return cost2;
    }
    
}
class MobilePhoneInProvinceRule  extends CallChargeRule{
    @Override
    public double calCost(ArrayList<CallRecord> callRecords) {
        double time = 0 ;
        double timereal ;
        double cost = 0;
        for(int i=0;i<callRecords.size();i++)
        {
            callRecords.get(i).getStartTime();
            callRecords.get(i).getEndTime();
            timereal = (callRecords.get(i).getEndTime().getTime()-callRecords.get(i).getStartTime().getTime())/60000.0;
            if(timereal>(int)timereal)
            {
                time = (int)timereal+1;
                cost = cost + 0.2 * time;
            }
            else
            {
                time = (int)timereal;
                cost = cost + 0.2 * time;
            }
        }
        String cost1 = String.format("%.1f",cost);
        double cost2 = Double.parseDouble(cost1);
//        System.out.println(cost2);
        return cost2;
    }
    
}
class SendMessageRule extends MessageChargeRule{

    @Override
    public double calCost(ArrayList<MessageRecord> messageRecords) {
        // TODO Auto-generated method stub
        return 0;
    }
    

}
class User {
    UserRecords userRecords = new UserRecords();
    double balance = 100;
    ChargeMode chargeMode;
    String number;
    public User(String number) {
        super();
        this.number = number;
    }
    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;
    }
    public double calBalance() {
        balance = balance - chargeMode.getMonthlyRent()-calCost();
        return balance;
    }
    public double calCost() {
        return chargeMode.calCost(userRecords);
    }
    public double getBalance() {
        return balance;
    }
}
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> callingRecordsInProvince = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> callingOutProvinceRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> answerInCityRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> answerInProvinceRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> answerOutProvinceRecords = new ArrayList<CallRecord>();
    private ArrayList<CallRecord> answerInLandRecords = new ArrayList<CallRecord>();
    private ArrayList<MessageRecord> sendMessageRecords = new ArrayList<MessageRecord>();
    private ArrayList<MessageRecord> receiveMessageRecords = new ArrayList<MessageRecord>();
    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 ArrayList<CallRecord> getCallingRecordsInProvince() {
        return callingRecordsInProvince;        
    }
    public ArrayList<CallRecord> getCallingOutProvinceRecords() {
        return callingOutProvinceRecords;
    }
    public ArrayList<CallRecord> getAnswerOutProvinceRecords() {
        return answerOutProvinceRecords;
    }
    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 answerRecord)
    {
        answerInCityRecords.add(answerRecord);
    }
    public void addAnswerInProvinceRecords(CallRecord answerRecord)
    {
        answerInProvinceRecords.add(answerRecord);
    }
    public void addAnswerInLandRecords(CallRecord answerRecord)
    {
        answerInLandRecords.add(answerRecord);
    }
    public void addSendMessageRecords(MessageRecord sendMeessageRecord)
    {
        sendMessageRecords.add(sendMeessageRecord);
    }
    public void addReceiveMessageRecords(MessageRecord receiveMessageRecord)
    {
        receiveMessageRecords.add(receiveMessageRecord);
    }
    public void addCallingRecordsInProvince(CallRecord callRecord)
    {
        callingRecordsInProvince.add(callRecord);
    }
    public void addCallingOutProvinceRecords(CallRecord callRecord)
    {
        callingOutProvinceRecords.add(callRecord);
    }
    public void addAnswerOutProvinceRecords(CallRecord callRecord)
    {
        answerOutProvinceRecords.add(callRecord);
    }
}

  

SourceMonitor生成的报表内容:

 

 

 类图

 

 

分析总结

   这一次作业是再上一次作业的基础上及进行改进的,本道题需要加入手机类,并对主类进行适当的修改,增加手机计费的规则,并在输入处判断是手机计费还是座机计费,这里要注意关于信息的测试点,千万不要掉进坑里去。

第八次作业第一题 

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:

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(短信记录)是它的子类。
 

image.png

图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.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

public class Main {

    public static ArrayList<User> users = new ArrayList<User>();
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
//        String ss = in.nextLine();
        while(true) {
            String str = in.nextLine();
            if(!str.equals("end")) {
                
                if(str.matches("[u]-1[0-9]{10}\\s[3]")) {
                    String[] s = str.split(" ");
                    
                    User user = new User(s[0].substring(2,s[0].length()));
                    users.add(user);
                }
                else if(str.matches("[m]-1[0-9]{10}\\s"+"1[0-9]{10}\\s"+"[a-zA-Z-z0-9-,\\.\\ ]+$"
)){
                    String[] s = str.split(" ",3);
                    users.get(getUser(s[0].substring(2,s[0].length()))).messageRecord.add(s[2]);
                }
            }
            else
                break;
        }
        Collections.sort(users, new Comparator<User>() {
            
                 public int compare(User user1, User user2) {
        
                   return user1.getNumber().compareTo(user2.getNumber());
            
                       }
            
                 });
        for(int i = 0;i<users.size();i++) {
            System.out.println(users.get(i).getNumber()+" "+String.format("%.1f", users.get(i).getCalCost())+" "+String.format("%.1f", users.get(i).getCalBalance()));
        }
    }
    
    //根据号码找到对应的用户
        public static int getUser(String s) {
            int n = 0;
            for(int i = 0;i<users.size();i++) {
                if(s.equals(users.get(i).getNumber())) {
                    n=i;
                }
            }
            return n;

}
}
class User{
    private String number;
    private double balance = 100;
    private double calBalance;
    private double calCost = 0;
    ArrayList<String> messageRecord = new ArrayList<String>();
    public String getNumber() {
        return this.number;
    }
    


    public User(String number) {
        super();
        this.number = number;
    }


    //计算用了多少话费
    public double getCalCost() {
        int n = 0;
        for(int i = 0;i<this.messageRecord.size();i++){
            
            if(Count(messageRecord.get(i))+n<=3) {
                
                this.calCost = this.calCost + 0.1*Count(messageRecord.get(i));
                n = n + Count(messageRecord.get(i));
                
            }
            else if(Count(messageRecord.get(i))+n>3&&Count(messageRecord.get(i))+n<=5) {
                if(n == 0) {
                    this.calCost = this.calCost + 0.1*3 + (Count(messageRecord.get(i))-3)*0.2;
                }
                else if(n==1) {
                    this.calCost = this.calCost + 0.1*2 + (Count(messageRecord.get(i))-2)*0.2;
                }
                else if(n==2) {
                    this.calCost = this.calCost + 0.1*1 + (Count(messageRecord.get(i))-1)*0.2;
                }
                else if(n>=3) {
                    this.calCost = this.calCost  + Count(messageRecord.get(i))*0.2;
                }
                n = n + Count(messageRecord.get(i));
            }
            else if(Count(messageRecord.get(i))+n>5) {
                if(n<=3)
                    this.calCost = this.calCost + (3-n)*0.1+2*0.2+(Count(messageRecord.get(i))-5+n)*0.3;
                else if(n==4) {
                    this.calCost = this.calCost +0.2+(Count(messageRecord.get(i))-1)*0.3;
                }
                else if(n>=5) {
                    this.calCost = this.calCost + Count(messageRecord.get(i))*0.3;
                }
                    
                n = n + Count(messageRecord.get(i));
            }
                
        }
        return this.calCost;
    }
    
    
    public double getCalBalance(){
        this.calBalance = this.balance - this.calCost;
        return this.calBalance;
    }
    
    
    
    
    //计算一次话费条数
    public int Count(String string) {
        int n = 0;
        if(string.length()%10==0) {
            n = string.length()/10;
        }
        else
            n = string.length()/10 + 1;
        return n;
    }
}  

SourceMonitor生成的报表内容:

 

 类图

 

 

分析总结

  这道题其实没有什么好多说的,就是在第六次,第七次作业的基础上修改一下即可,难度明显要下降了很多。就是改写一下短信类,对主类进行适度的修改即可。还有,短信计费是分段计费,这一点要注意一下。

三、踩坑心得 

  1. 关于输入的问题,我在这里踩了好长时间的坑,收入的有效性的问题还是没法有效解决,最一开始没用正则表达和式,最后使用了正则表达式解决了这一问题。
  2. 判断通话记录是只盯着电话号的位数而忽略了电话号码是否是数字的问题。
  3. 注意日期的合法性。
  4. 忽略重复开户的操作。
  5. 做题时先审题目,而不是为了做题而做题,先去想好怎么做再去敲代码。我本人经常性的触犯这些错误。

四、改进建议

前三次作业最大的问题就是披着java的外衣,但是里面全是C语言的肉,在一个类里面将所有问题解决。使用类使程序发挥java的优势,调用方法使程序更有层次性,可以规避面向过程的编程中出现的需要很麻烦才能解决的问题,在字符串处理上更加改进,避免误差,可以采用正则表达式,来省去很大的冗余。通过前几次的作业以及学习,前面说的问题得到了较大的改善。前几次作业这种情况发生了显著的改变,懂得了识别对象并创造相应的类,让他们分开工作,增加代码的可读性。在编程的过程中尽量不要粗心,出现类名前后不一致的情况。输入的过程可以尝试使用正则表达式。从这几次作业的情况来看,类的抽象类,容器类以及正则表达式理解还不是那么的深刻,还是要多加练习。

五、总结

  1. 我在这三次作业中初步学会了java的基本语法,它与C语言有着很大出入,总结一下就是长着类似的肉,但是二者的根骨不同。
  2. 在这三次的作业中,我做得并不理想,首先最开始没有采用面向对象的思想,,很多刁钻的测试点根本就没得分。最后就是有关的概念理解的不是那么透彻。在今后的学习中,要深化对抽象类和容器类以及正则表达式的理解,学会运用网络资源搜寻程序所需相关函数,做得对程序精益求精,争取在现场的作业里做得更好。
  3. 在题目拿到手时,常常不知道从何处下手,同时还存在着考虑问题不全面的情况。
  4. 总的来说,这三次的作业比前几次作业要简单的多,只需按照它给出的类图编程即可。

标签:return,String,double,ArrayList,博客,new,public,第三次
From: https://www.cnblogs.com/zhangjingyang/p/16972064.html

相关文章

  • EDUL的第三次博客
    一、前言:几次的大作业还是比较简单的,只需要按照题目给出的类图,对应的写出相应的类,框架已经给出,你只需要填充就行了,多看几遍题目的类图,理清类之间的关联差不多就能写出......
  • 第三次总结
    一、前言: 到目前为止,我们共进行了pta八次大作业和一次期中考试,其中前三次大作业在第一次的blog中已经做了分析,四、五次大作业在第二次的blog中做出了分析,那么这次blog就......
  • 写博客目的及今年目标
         本人希望能通过写博客这一种方式来更好的整理自己的知识体系和记录自己的疑问留待以后解决。我看视频只能集中学习十分钟便会精力涣散,看书可以支持半小时左......
  • 第三次博客
    第三次博客目录第三次博客前言设计与分析题目集6——7-1电信计费系列1-座机计费①题目及分析②分析③代码题目集6——7-2多态测试①题目及分析②分析③代码④总结与分析......
  • 第三次博客
    目录一、前言二、设计与分析第六次作业7-1电信计费系列1-座机计费题目代码展示类图代码报表分析解释与心得第七次大作业7-1电信计费系列2-手机+座机计费题目代码展示类图生......
  • 为什么不建议在华为技术论坛(昇腾论坛/mindspore技术论坛)发表帖子和技术博客
    华为的硬件设计技术在国内没得说,华为的硬件制造技术基本就没听说过,而华为的软件技术可是出了名的不咋样。一年前曾经在昇腾的页面进入到华为技术论坛,并且发了几篇关于minds......
  • 开发工具系列005-Hexo + gitub搭建个人博客教程
    title:开发工具系列005-Hexo+Github搭建个人博客tags:-网络编程系列categories:[]date:2015-06-2813:12:131.0说明其实,搭建个人博客的技术方案有很多。......
  • 开发工具系列005-Hexo + gitub搭建个人博客教程
    title:开发工具系列005-Hexo+Github搭建个人博客tags:-网络编程系列categories:[]date:2015-06-2813:12:131.0说明其实,搭建个人博客的技术方案有很多。......
  • pta第三次博客
    目录pta第三次博客1.前言2.设计与分析第6次作业第一题第6次作业第二题第七次作业第一题第七次作业第二题第七次作业第三题第八次作业第一题第八次作业第二题第八次作业第三......
  • 第三次博客
    目录第三次博客电信计费一、前言二、设计与分析1.第六次大作业电信计费系列1-座机计费思路总结改进建议2.第七次大作业电信计费系列2-手机+座机计费思路分析改进建议3.第......