1. 程式人生 > 其它 >PTA第三次BLOG

PTA第三次BLOG

一、前言

  1. PTA題目集6:剛開始見到這個題目集的時候,發現這個題目集實質上並不是難度高,因為它不像之前的四邊形,五邊形一樣要求你去構造正確的演算法,求得一個正確的結果,對於電信計費的情況,其計算十分的簡單,無非就是計算每條通話記錄的通話時間,然後根據收費規則求得其費用,然後求和即可。但我認為其難度也不小,主要難點在於這是一個系統,也就意味著會有許多的類,如何構建安排處理好各個類成為了首要的難題。即便老師一開始就給了類圖,但當拿到類圖的時候也看了好一段時間才逐漸理解類圖中各個類的構建及其關係。更不用說如果要自己從零開始構建類的關係的話,會有多難於起步了。

  2. PTA題目集7:其同樣是電信計費的題目,如果說之前的題目集合6是讓我們初步構建起來電信計費系列的框架,並且理解各個類之間的關係和聯絡的話。那麼這次題目集應該算是自己在初步瞭解了這個系統之後,考驗自己對於這個系統的拓展能力。包括如何新增手機,構建新的收費類別,怎麼處理與之前的關係等等。這裡並沒有像第一次那樣給出明明白白的類圖,而是要自己根據自己的理解,練習出一定的拓展能力。

  3. PTA題目集8:題目集8其實就比較的簡單了,經過了題目集7後,其實對於整個系統的構造已經有了比較完整的理解,而在題目集7中也完成了對於系統拓展,所以題目集8其實已經算是小case了,同樣是拓展,那麼構造類以及處理關係已經有了一定的經驗,主要步驟也是構建新的收費方式,改正則,由於沒有那麼多的種類,因此我認為在電信系列中,這個題目集算是最簡單的了。

二、設計與分析

PTA題目集6-電信計費系列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”結束。

  2. 題目設計
    顯然,對於輸入的資料,有資料屬於開戶,有的資料屬於新增通話記錄。

    對於輸入的資料屬於開戶:
    ①首先肯定是要通過正則表示式來判斷是否手機號符合規則
    ②對於正確的資料,那麼將其提取建立為一個使用者,新增到使用者列表中

    對於輸入的資料屬於通話記錄:
    ①首先也還是要通過正則表示式來判斷通話雙方,時間等是否規範
    ②提取通話的雙方,包括其地區碼,通話時間,然後根據這些建立一個新的通話記錄
    ③搜尋使用者列表,根據通話的雙發,將該通話記錄插入到對應使用者的撥打/接聽的記錄中去

    對於座機的三個收費模式:
    可以構建分別構建三個類,標明為座機在室內,在省內,在國內的通話收費標準
    並將其新增到收費規則列表中去

  3. 完整程式碼

     import java.text.DateFormat;
     import java.text.ParseException;
     import java.text.SimpleDateFormat;
     import java.util.*;
    
     public class Main {
         public static void main(String[] args){
             ArrayList<String> inputList=Input.getAllInput();
             inputList=Input.deleteCoincide(inputList);
             Format.trueInputFormat(inputList);
             Handle.userRecords(inputList);
         }
    
     }
    
     class Handle{
         public static void userRecords(ArrayList<String> inputList){
             ArrayList<User> users=Input.initUser(inputList);
             Collections.sort(users);
             for(User user:users){
                 System.out.println(user.number+" "+Format.Format_Str(user.calCost(),2)+" "+Format.Format_Str(user.calBalance(),2));
             }
         }
     }
    
     class Input{
         public static ArrayList<String> getAllInput(){
             ArrayList<String> inputList=new ArrayList<String>();
             Scanner input=new Scanner(System.in);
             String info=input.nextLine();
             while (!info.equals("end")) {
                 inputList.add(info);
                 info=input.nextLine();
             }
             return inputList;
         }
    
         public static ArrayList<String> deleteCoincide(ArrayList<String> inputList){
             ArrayList<String> newList=new ArrayList<String>();
             for(String s:inputList){
                 if(!Input.isExist(s,newList))
                     newList.add(s);
             }
             return newList;
         }
    
         public static boolean isExist(String s,ArrayList<String> sList){
             for(String input:sList){
                 if(input.equals(s))
                     return true;
             }
             return false;
         }
    
         public static ArrayList<User> initUser(ArrayList<String> inputList){
             ArrayList<User> users=new ArrayList<User>();
             for(String s:inputList){
                 if(s.charAt(0)=='u'){
                     User newUser=new User(s);
                     users.add(newUser);
                 }
                 else if(s.charAt(0)=='t'){
                     CallRecord callRecord=new CallRecord(s);
                     Input.addRecord(users,callRecord);
                 }
             }
             return users;
         }
    
         private static void addRecord(ArrayList<User> users, CallRecord callRecord) {
             for (User user:users){
                 if(user.number.equals(callRecord.callingNumber)){
                     if(callRecord.callingAddressAreaCode.equals(callRecord.answerAddressAreaCode))
                         user.userRecords.addCallingInCityRecords(callRecord);
                     else if(Input.areaCodeInProvince(callRecord.answerAddressAreaCode))
                         user.userRecords.addCallingInProvinceRecords(callRecord);
                     else
                         user.userRecords.addCallingInLandRecords(callRecord);
                 }
                 if(user.number.equals(callRecord.answerNumber)){
                     if(callRecord.callingAddressAreaCode.equals(callRecord.answerAddressAreaCode))
                         user.userRecords.addAnswerInCityRecords(callRecord);
                     else if(Input.areaCodeInProvince(callRecord.callingAddressAreaCode))
                         user.userRecords.addAnswerInProvinceRecords(callRecord);
                     else
                         user.userRecords.addAnswerInLandRecords(callRecord);
                 }
             }
         }
    
         public static boolean areaCodeInProvince(String areaCode){
             //0790~0799以及0701
             String[] AreaCode=new String[]{"0790","0791","0792","0793","0794","0795","0796","0797","0798","0799","0701"};
             for(int i=0;i<AreaCode.length;i++){
                 if(areaCode.equals(AreaCode[i]))
                     return true;
             }
             return false;
         }
     }
    
     class Format {
         public static double Format_Str(double s,int num) {
             String s1=String.format("%."+num+"f",s);
             s=Double.parseDouble(s1);
             return s;
         }
    
         public static void trueInputFormat(ArrayList<String> inputList){
             for(int i=0;i<inputList.size();){
                 String s=inputList.get(i);
                 if(!s.matches("[u]-[0][7]([9][0-9]|[0][1])[0-9]{7,8} [0-3]")==true&&!s.matches("^t\\-0\\d{9,11}\\s0\\d{9,11}((\\s\\d{4}\\.([1-9]|([1]{1}[0-2]{1}))\\.([1-9]|([1-2]{1}[0-9]{1})|3[0-1])\\s(([0-1][0-9])|(2[0-3]))\\:([0-5][0-9])\\:([0-5][0-9])){2})")==true){
                     inputList.remove(i);
                 }
                 else i++;
             }
         }
     }
     //使用者類
     class User implements Comparable<User>{
         String number;
         double balance;
         UserRecords userRecords=new UserRecords();//儲存通話記錄
         ChargeMode chargeMode;
         public User(String user){
             String[] s=user.split("[-\\s]");
             this.number=s[1];
             this.chargeMode=new LandlinePhoneCharging();
             this.balance=100;
         }
    
         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 getBalance() {
             return balance;
         }
    
         public double calBalance(){
             this.balance=this.balance-this.calCost()-this.chargeMode.getMonthlyRent();
             return this.balance;
         }
    
         public double calCost(){
             return this.chargeMode.calCost(this.userRecords);
         }
    
         @Override
         public int compareTo(User user) {
             long a=Long.parseLong(this.number);
             long b=Long.parseLong(user.number);
             if(a-b<0) return -1;
             else return 1;
         }
     }
     //通話記錄類
     class UserRecords{
         ArrayList<CallRecord> callingInCityRecords=new ArrayList<CallRecord>();//在市內撥打
         ArrayList<CallRecord> callingInProvinceRecords=new ArrayList<CallRecord>();//在省內撥打
         ArrayList<CallRecord> callingInLandRecords=new ArrayList<CallRecord>();//在國內撥打
         ArrayList<CallRecord> answerInCityRecords=new ArrayList<CallRecord>();//在市內接聽
         ArrayList<CallRecord> answerInProvinceRecords=new ArrayList<CallRecord>();//在省內接聽
         ArrayList<CallRecord> answerInLandRecords=new ArrayList<CallRecord>();//在國內接聽
    
         public ArrayList<CallRecord> getAnswerInCityRecords() {
             return answerInCityRecords;
         }
    
         public ArrayList<CallRecord> getAnswerInProvinceRecords() {
             return answerInProvinceRecords;
         }
    
         public ArrayList<CallRecord> getAnswerInLandRecords() {
             return answerInLandRecords;
         }
    
         public ArrayList<CallRecord> getCallingInCityRecords() {
             return callingInCityRecords;
         }
    
         public ArrayList<CallRecord> getCallingInProvinceRecords() {
             return callingInProvinceRecords;
         }
    
         public ArrayList<CallRecord> getCallingInLandRecords() {
             return callingInLandRecords;
         }
    
         public void addCallingInCityRecords(CallRecord callRecord) {
             this.callingInCityRecords.add(callRecord);
         }
    
         public void addCallingInProvinceRecords(CallRecord callRecord) {
             this.callingInProvinceRecords.add(callRecord);
         }
    
         public void addCallingInLandRecords(CallRecord callRecord) {
             this.callingInLandRecords.add(callRecord);
         }
    
         public void addAnswerInCityRecords(CallRecord callRecord) {
             this.answerInCityRecords.add(callRecord);
         }
    
         public void addAnswerInLandRecords(CallRecord callRecord) {
             this.answerInLandRecords.add(callRecord);
         }
    
         public void addAnswerInProvinceRecords(CallRecord callRecord) {
             this.answerInProvinceRecords.add(callRecord);
         }
     }
    
     abstract class communicationRecord{
         String callingNumber;
         String answerNumber;
         public communicationRecord(String Record){
             String[] s=Record.split("[-\\s]");
             this.callingNumber=s[1];
             this.answerNumber=s[2];
         }
    
         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;
         public CallRecord(String callRecord){
             super(callRecord);
             DateFormat df = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
             String[] s=callRecord.split("[-\\s]");
             try {
                 this.startTime=df.parse(s[3]+" "+s[4]);
                 this.endTime=df.parse(s[5]+" "+s[6]);
             }
             catch (ParseException e){
                 System.out.println("Wrong Format");
                 System.exit(0);
             }
             this.callingAddressAreaCode=s[1].substring(0,4);
             this.answerAddressAreaCode=s[2].substring(0,4);
         }
         String callingAddressAreaCode;
         String answerAddressAreaCode;
     }
    
     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();
     }
     class LandlinePhoneCharging extends ChargeMode{
         double mothlyRent=20;
         public LandlinePhoneCharging(){
             this.chargeRules.add(new LandPhoneInCityRule());
             this.chargeRules.add(new LandPhoneInProvinceRule());
             this.chargeRules.add(new LandPhoneInlandRule());
         }
         @Override
         public double calCost(UserRecords userRecords) {
             double cost=0;
             cost+=this.chargeRules.get(0).calCost(userRecords.getCallingInCityRecords());
             cost+=this.chargeRules.get(1).calCost(userRecords.getCallingInProvinceRecords());
             cost+=this.chargeRules.get(2).calCost(userRecords.getCallingInLandRecords());
             return cost;
         }
    
         @Override
         public double getMonthlyRent() {
             return this.mothlyRent;
         }
     }
     abstract class ChargeRule{
         public abstract double calCost(ArrayList<CallRecord> callRecords);
     }
     abstract class CallChargeRule extends ChargeRule{
     }
     class LandPhoneInCityRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 long sec=(callRecord.endTime.getTime()-callRecord.startTime.getTime())/1000;
                 min=sec/60;
                 if(sec%60!=0)
                     min+=1;
                 cost+=0.1*min;
             }
             return cost;
         }
     }
     class LandPhoneInProvinceRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 long sec=(callRecord.endTime.getTime()-callRecord.startTime.getTime())/1000;
                 min=sec/60;
                 if(sec%60!=0)
                     min+=1;
                 cost+=0.3*min;
             }
             return cost;
         }
     }
     class LandPhoneInlandRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 long sec=(callRecord.endTime.getTime()-callRecord.startTime.getTime())/1000;
                 min=sec/60;
                 if(sec%60!=0)
                     min+=1;
                 cost+=0.6*min;
             }
             return cost;
         }
     }
    
  4. SourceMonitor分析

    Kiviat Graph分析
    ①註釋分析:由於依照類圖構建的程式碼,寫了部分註釋幫助記憶
    ②每個類中方法數分析:每個類裡面的方法比較的少,因為題目只需要實現計費,不像多邊形這樣的,並不需要太多其他的方法。
    ③每個方法中有效程式碼行數分析:每個方法中的有效語句較少,比較的簡短,有些可能一個方法只有一個return(點名get語句)
    ④最大圈複雜度分析:最大圈複雜度比較高,因為在插入通話記錄時使用了較多迴圈。
    ⑤最大深度分析:最大深度比較理想
    ⑥平均深度分析:平均深度也比較理想,但也可以適當優化。
    ⑦平均圈複雜度分析:平均圈複雜度比較低,說明程式設計的還是比較合理的。

    Block Histogram分析
    深度多數集中在1-3,這也印證了之前的最大深度以及平均深度。

PTA題目集7-電信計費系列2-手機+座機計費

  1. 題目內容
    實現南昌市電信分公司的計費程式,假設該公司針對手機和座機使用者分別採取了兩種計費方案,分別如下:
    1、針對市內座機使用者採用的計費方式(與電信計費系列1內容相同):
    月租20元,接電話免費,市內撥打電話0.1元/分鐘,省內長途0.3元/分鐘,國內長途撥打0.6元/分鐘。不足一分鐘按一分鐘計。
    假設本市的區號:0791,江西省內各地市區號包括:0790~0799以及0701。
    2、針對手機使用者採用實時計費方式:
    月租15元,市內省內接電話均免費,市內撥打市內電話0.1元/分鐘,市內撥打省內電話0.2元/分鐘,市內撥打省外電話0.3元/分鐘,省內漫遊打電話0.3元/分鐘,省外漫遊接聽0.3元/分鐘,省外漫遊撥打0.6元/分鐘;
    注:被叫電話屬於市內、省內還是國內由被叫電話的接聽地點區號決定,比如以下案例中,南昌市手機使用者13307912264在區號為020的廣州接聽了電話,主叫號碼應被計算為撥打了一個省外長途,同時,手機使用者13307912264也要被計算省外接聽漫遊費:
    u-13307912264 1
    t-079186330022 13307912264 020 2022.1.3 10:00:25 2022.1.3 10:05:11

    輸入資訊包括兩種型別
    1、逐行輸入南昌市使用者開戶的資訊,每行一個使用者,含手機和座機使用者
    格式:u-號碼 計費型別 (計費型別包括:0-座機 1-手機實時計費 2-手機A套餐)
    例如:u-079186300001 0
    座機號碼由區號和電話號碼拼接而成,電話號碼包含7-8位數字,區號最高位是0。
    手機號碼由11位數字構成,最高位是1。
    本題在電信計費系列1基礎上增加型別1-手機實時計費。
    手機設定0或者座機設定成1,此種錯誤可不做判斷。
    2、逐行輸入本月某些使用者的通訊資訊,通訊資訊格式:
    座機呼叫座機:t-主叫號碼 接聽號碼 起始時間 結束時間
    t-079186330022 058686330022 2022.1.3 10:00:25 2022.1.3 10:05:11
    以上四項內容之間以一個英文空格分隔,
    時間必須符合"yyyy.MM.dd HH:mm:ss"格式。提示:使用SimpleDateFormat類。
    輸入格式增加手機接打電話以及收發簡訊的格式,手機接打電話的資訊除了號碼之外需要額外記錄撥打/接聽的地點的區號,比如:
    座機打手機:
    t-主叫號碼 接聽號碼 接聽地點區號 起始時間 結束時間
    t-079186330022 13305862264 020 2022.1.3 10:00:25 2022.1.3 10:05:11
    手機互打:
    t-主叫號碼 撥號地點 接聽號碼 接聽地點區號 起始時間 結束時間
    t-18907910010 0791 13305862264 0371 2022.1.3 10:00:25 2022.1.3 10:05:11

    注意:以上兩類資訊,先輸入所有開戶資訊,再輸入所有通訊資訊,最後一行以“end”結束。

  2. 題目設計

    在前言中也說過了,這裡無非就是在PTA題目集6上額外新增一些內容,因為手機的加入,導致
    出現了手機撥打座機,座機撥打手機,手機撥打手機等等情況。

    對於使用者的建立:
    ①在PTA6的基礎上,更正正則表示式,使得能判斷正確的手機號以及座機號
    ②其他倒不需要更改太多,建立的手機使用者一樣和座機使用者放在同一個使用者表中

    對於通話記錄的插入:
    ①插入方式其實不需要太大的改動,同樣是根據撥打以及接聽的號碼,查詢到對應的使用者,插入到使用者類的對應的通話記錄中去
    ②需要對資料進行額外的鑑別,因為對於座機來說,地區號為其號碼前3-4位,而手機的位置會發生變化,因此通話記錄中,手機
    號後會有一個表示手機所在區號的資訊,因此,需要更改建立新的通話記錄的程式碼,其要適應新的通話記錄格式。
    ③當然,主要是新增了三種記錄,座機撥打手機,手機撥打座機,手機撥打手機,而原本的座機撥打座機的程式碼可以不用更改。

    對於手機計費方式:
    ①顯然,手機的計費方式和座機的大不相同,但是,仍舊可以按照每個計費策略建立一個類的方式,來建立計費規則
    ②分析可得,手機對於自己在市內,省內,國內等地區的撥打和接聽電話的收費可以各自建立一個類,因為部分情況下手機接聽
    電話也會扣費,而座機接聽電話免費。
    ③新建立的計費規則依舊繼承收費類,實現計算花費的方法,並同樣將每個計費規則新增到手機使用者的計費規則列表中去

  3. 完整原始碼(其中多餘的部分是在之後的題目中新增的,本題中用不到)

     import java.text.DateFormat;
     import java.text.ParseException;
     import java.text.SimpleDateFormat;
     import java.util.*;
     public class Main {
         public static void main(String[] args){
             ArrayList<String> inputList=Input.getAllInput();
             inputList=Input.deleteCoincide(inputList);
             Format.trueInputFormat(inputList);
             Handle.userRecords(inputList);
         }
    
     }
    
     class Handle{
         public static void userRecords(ArrayList<String> inputList){
             ArrayList<User> users=Input.initUser(inputList);
             Collections.sort(users);
             for(User user:users){
                 System.out.println(user.number+" "+Format.Format_Str(user.calCost(),2)+" "+Format.Format_Str(user.calBalance(),2));
             }
         }
     }
    
     class Input{
         public static ArrayList<String> getAllInput(){
             ArrayList<String> inputList=new ArrayList<String>();
             Scanner input=new Scanner(System.in);
             String info=input.nextLine();
             while (!info.equals("end")) {
                 inputList.add(info);
                 info=input.nextLine();
             }
             return inputList;
         }
    
         public static ArrayList<String> deleteCoincide(ArrayList<String> inputList){
             ArrayList<String> newList=new ArrayList<String>();
             for(String s:inputList){
                 if(!Input.isExist(s,newList))
                     newList.add(s);
             }
             return newList;
         }
    
         public static boolean isExist(String s,ArrayList<String> sList){
             for(String input:sList){
                 if(input.equals(s))
                     return true;
             }
             return false;
         }
    
         public static ArrayList<User> initUser(ArrayList<String> inputList){
             ArrayList<User> users=new ArrayList<User>();
             ArrayList<String> newInput=new ArrayList<String>();
             for(String s:inputList){
                 if(s.charAt(0)=='u'){
                     User newUser=new User(s);
                     users.add(newUser);
                 }
                 else if(s.charAt(0)=='t'){
                     CallRecord callRecord=new CallRecord(s);
                     Input.addRecord(users,callRecord);
                 }
             }
             return users;
         }
    
         private static void addRecord(ArrayList<User> users, CallRecord callRecord) {
             for (User user:users){
                 if(user.number.equals(callRecord.callingNumber)){
                     if(callRecord.callingAddressAreaCode.equals("0791"))
                         user.userRecords.addCallingInCityRecords(callRecord);
                     else if(Input.areaCodeInProvince(callRecord.callingAddressAreaCode))
                         user.userRecords.addCallingInProvinceRecords(callRecord);
                     else
                         user.userRecords.addCallingInLandRecords(callRecord);
                 }
                 if(user.number.equals(callRecord.answerNumber)){
                     if(callRecord.answerAddressAreaCode.equals("0791"))
                         user.userRecords.addAnswerInCityRecords(callRecord);
                     else if(Input.areaCodeInProvince(callRecord.answerAddressAreaCode))
                         user.userRecords.addAnswerInProvinceRecords(callRecord);
                     else
                         user.userRecords.addAnswerInLandRecords(callRecord);
                 }
             }
         }
    
         public static boolean areaCodeInProvince(String areaCode){
             //0790~0799以及0701
             String[] AreaCode=new String[]{"0790","0791","0792","0793","0794","0795","0796","0797","0798","0799","0701"};
             for(int i=0;i<AreaCode.length;i++){
                 if(areaCode.equals(AreaCode[i]))
                     return true;
             }
             return false;
         }
     }
    
     class Format {
         public static double Format_Str(double s,int num) {
             String s1=String.format("%."+num+"f",s);
             s=Double.parseDouble(s1);
             return s;
         }
    
         public static void trueInputFormat(ArrayList<String> inputList){
             for(int i=0;i<inputList.size();){
                 String s=inputList.get(i);
                 if (s.matches("[u]-0791[0-9]{7,8}\\s[0]") || s.matches("[u]-1[0-9]{10}\\s[1]")) {
                     i++;
                 } else if (s.matches("(([t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s)|"
                         + "([t]-0791[0-9]{7,8}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s)|"
                         + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "0[0-9]{9,11}\\s)|"
                         + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\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])")) {
                     i++;
                 }
                 else inputList.remove(i);
             }
         }
     }
    
     class User implements Comparable<User>{
         String number;
         double balance;
         UserRecords userRecords=new UserRecords();
         ChargeMode chargeMode;
         public User(String user){
             String[] s=user.split("[-\\s]");
             this.number=s[1];
             if(s[s.length-1].equals("0")){
                 this.chargeMode=new LandlinePhoneCharging();
             }
             else {
                 this.chargeMode=new MobilePhoneCharging();
             }
             this.balance=100;
         }
    
         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 getBalance() {
             return balance;
         }
    
         public double calBalance(){
             this.balance=this.balance-this.calCost()-this.chargeMode.getMonthlyRent();
             return this.balance;
         }
    
         public double calCost(){
             return this.chargeMode.calCost(this.userRecords);
         }
    
         @Override
         public int compareTo(User user) {
             if(this.number.compareTo(user.number)<0) return -1;
             else return 1;
         }
     }
    
     class UserRecords{
         ArrayList<CallRecord> callingInCityRecords=new ArrayList<CallRecord>();
         ArrayList<CallRecord> callingInProvinceRecords=new ArrayList<CallRecord>();
         ArrayList<CallRecord> callingInLandRecords=new ArrayList<CallRecord>();
         ArrayList<CallRecord> answerInCityRecords=new ArrayList<CallRecord>();
         ArrayList<CallRecord> answerInProvinceRecords=new ArrayList<CallRecord>();
         ArrayList<CallRecord> answerInLandRecords=new ArrayList<CallRecord>();
    
         public ArrayList<CallRecord> getAnswerInCityRecords() {
             return answerInCityRecords;
         }
    
         public ArrayList<CallRecord> getAnswerInProvinceRecords() {
             return answerInProvinceRecords;
         }
    
         public ArrayList<CallRecord> getAnswerInLandRecords() {
             return answerInLandRecords;
         }
    
         public ArrayList<CallRecord> getCallingInCityRecords() {
             return callingInCityRecords;
         }
    
         public ArrayList<CallRecord> getCallingInProvinceRecords() {
             return callingInProvinceRecords;
         }
    
         public ArrayList<CallRecord> getCallingInLandRecords() {
             return callingInLandRecords;
         }
    
         public void addCallingInCityRecords(CallRecord callRecord) {
             this.callingInCityRecords.add(callRecord);
         }
    
         public void addCallingInProvinceRecords(CallRecord callRecord) {
             this.callingInProvinceRecords.add(callRecord);
         }
    
         public void addCallingInLandRecords(CallRecord callRecord) {
             this.callingInLandRecords.add(callRecord);
         }
    
         public void addAnswerInCityRecords(CallRecord callRecord) {
             this.answerInCityRecords.add(callRecord);
         }
    
         public void addAnswerInLandRecords(CallRecord callRecord) {
             this.answerInLandRecords.add(callRecord);
         }
    
         public void addAnswerInProvinceRecords(CallRecord callRecord) {
             this.answerInProvinceRecords.add(callRecord);
         }
     }
    
     abstract class communicationRecord{
         String callingNumber;
         String answerNumber;
         public communicationRecord(String Record){
             String[] s=Record.split("[-\\s]");
             switch (s.length){
                 case 7:
                 case 8:
                     this.callingNumber=s[1];
                     this.answerNumber=s[2];
                     break;
                 case 9:
                     this.callingNumber=s[1];
                     this.answerNumber=s[3];
             }
    
         }
    
         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;
         public CallRecord(String callRecord){
             super(callRecord);
             DateFormat df = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
             String[] s=callRecord.split("[-\\s]");
             //提取通話時間
             try {
                 this.startTime=df.parse(s[s.length-4]+" "+s[s.length-3]);
                 this.endTime=df.parse(s[s.length-2]+" "+s[s.length-1]);
             }
             catch (ParseException e){
                 System.out.println("Wrong Format");
                 System.exit(0);
             }
             //提取通話區號
             switch (s.length){
    
                 case 7:
                     this.callingAddressAreaCode=s[1].substring(0,4);
                     this.answerAddressAreaCode=s[2].substring(0,4);
                     break;
                 case 8:
                     if(s[2].length()==3||s[2].length()==4){
                         this.callingAddressAreaCode=s[2];
                         this.answerAddressAreaCode=s[3].substring(0,4);
                     }
                     else{
                         this.callingAddressAreaCode=s[1].substring(0,4);
                         this.answerAddressAreaCode=s[3];
                     }
                     break;
                 case 9:
                     this.callingAddressAreaCode=s[2];
                     this.answerAddressAreaCode=s[4];
             }
    
         }
    
         public long getCallTime(){
             long sec=(this.endTime.getTime()-this.startTime.getTime())/1000;
             long min=sec/60;
             if(sec%60!=0)
                 min+=1;
             return min;
         }
         String callingAddressAreaCode;
         String answerAddressAreaCode;
     }
    
     abstract class ChargeMode{
         ArrayList<ChargeRule> chargeRules=new ArrayList<>();
    
         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();
     }
     class LandlinePhoneCharging extends ChargeMode{
         double mothlyRent=20;
         public LandlinePhoneCharging(){
         }
         @Override
         public double calCost(UserRecords userRecords) {
             double cost=0;
             cost+=new LandPhoneInCityRule().calCost(userRecords.getCallingInCityRecords());
             return cost;
         }
    
         @Override
         public double getMonthlyRent() {
             return this.mothlyRent;
         }
     }
    
     class MobilePhoneCharging extends ChargeMode{
         double mothlyRent=15;
         public MobilePhoneCharging(){
         }
         @Override
         public double calCost(UserRecords userRecords) {
             double cost=0;
             cost+=new MobilePhoneCallInCityRule().calCost(userRecords.getCallingInCityRecords());
             cost+=new MobilePhoneCallInProvinceRule().calCost(userRecords.getCallingInProvinceRecords());
             cost+=new MobilePhoneCallInlandRule().calCost(userRecords.getCallingInLandRecords());
             cost+=new MobilePhoneAnswerInlandRule().calCost(userRecords.getAnswerInLandRecords());
             return cost;
         }
    
         @Override
         public double getMonthlyRent() {
             return this.mothlyRent;
         }
     }
     abstract class ChargeRule{
     }
     abstract class CallChargeRule extends ChargeRule{
         public abstract double calCost(ArrayList<CallRecord> callRecords);
     }
     class LandPhoneInCityRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 min=callRecord.getCallTime();
                 if(callRecord.answerAddressAreaCode.equals("0791"))
                     cost+=0.1*min;
                 else if(Input.areaCodeInProvince(callRecord.answerAddressAreaCode))
                     cost+=0.3*min;
                 else cost+=0.6*min;
             }
             return cost;
         }
     }
     class LandPhoneInProvinceRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 cost+=0;
             }
             return cost;
         }
     }
     class LandPhoneInlandRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 cost+=0;
             }
             return cost;
         }
     }
    
     class MobilePhoneCallInCityRule extends CallChargeRule{
    
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 min=callRecord.getCallTime();
                 if(callRecord.answerAddressAreaCode.equals("0791"))
                     cost+=0.1*min;
                 else if(Input.areaCodeInProvince(callRecord.answerAddressAreaCode))
                     cost+=0.2*min;
                 else cost+=0.3*min;
             }
             return cost;
         }
     }
    
     class MobilePhoneAnswerInCityRule extends CallChargeRule{
    
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             return 0;
         }
     }
    
     class MobilePhoneCallInProvinceRule extends CallChargeRule{
    
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 min=callRecord.getCallTime();
                 cost+=0.3*min;
             }
             return cost;
         }
     }
    
     class MobilePhoneAnswerInProvinceRule extends CallChargeRule{
    
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             return 0;
         }
     }
    
     class MobilePhoneCallInlandRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 min=callRecord.getCallTime();
                 cost+=0.6*min;
             }
             return cost;
         }
     }
    
     class MobilePhoneAnswerInlandRule extends CallChargeRule{
         @Override
         public double calCost(ArrayList<CallRecord> callRecords) {
             double cost=0;
             long min;
             for(CallRecord callRecord:callRecords){
                 min=callRecord.getCallTime();
                 cost+=0.3*min;
             }
             return cost;
         }
     }
    
  4. SourceMonitor分析

    Kiviat Graph分析
    ①註釋分析:懶得寫註釋點jpg(我的程式碼只有我能看懂hhhh)
    ②每個類中方法數分析:每個類中的方法也比較少
    ③每個方法中有效程式碼行數分析:每個方法中的有效語句較少,即方法分的太細
    ④最大圈複雜度分析:最大圈複雜度比較高,可能原因是幾次for迴圈查詢使用者和插入記錄
    ⑤最大深度分析:最大深度還比較適中
    ⑥平均深度分析:平均深度在合適的範圍內,但可以再優化一下
    ⑦平均圈複雜度分析:平均圈複雜度比較的低

    Block Histogram分析
    顯然可以看出,深度的主要集中在1,2,即程式碼並不複雜

PTA題目集8-電信計費系列3-簡訊計費

  1. 題目內容
    實現一個簡單的電信計費程式,針對手機的簡訊採用如下計費方式:
    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. 題目設計

    簡訊計費其實和通話計費差不了太多,我認為簡訊計費甚至更簡單一點,因為其不像通話記錄一樣需要分市內,省內,國內的
    情況去討論,而且其實本道題和之前的題目切合度不高,可以刪除之前的通話記錄的程式碼,保證整個流程更加的清晰

    同樣,建立一個簡訊收費類,依照通話記錄的模式,同樣通過正則判斷,然後把資料存入到相應的使用者內,計算費用即可。
    唯一的區別是這個收費類需要根據簡訊的長度來計算,而不是固定的每個字多少錢,當然,實現了類的設計,計算部分的難度都不大

  3. 完整原始碼

     import java.util.*;
     class User {
         private UserRecords userRecords;//使用者記錄
         private double balance = 100;//餘額
         private ChargeMode chargeMode;//計費方式
         private String number;//號碼
    
         public double calBalance(){
             return balance - (chargeMode.getMonthlyRent() + chargeMode.calCost(userRecords));
         }
         public double calCost(){
             return chargeMode.calCost(userRecords);
         }
    
         public UserRecords getUserRecords() {
             return userRecords;
         }
    
         public void setUserRecords(UserRecords userRecords) {
             this.userRecords = userRecords;
         }
    
         public double getBalance() {
             return balance;
         }
    
         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;
         }
     }
    
    
     abstract class ChargeMode {
         protected List<ChargeRule> chargeRules = new ArrayList<>();
    
         public List<ChargeRule> getChargeRules() {
             return chargeRules;
         }
    
         public void setChargeRules(List<ChargeRule> chargeRules) {
             this.chargeRules = chargeRules;
         }
    
         abstract public double calCost(UserRecords userRecords);
    
         abstract public double getMonthlyRent();
    
     }
    
     class UserRecords {
         List<CallRecord> callingInCityRecords = new ArrayList<>();
         List<CallRecord> callingInProvinceRecords = new ArrayList<>();
         List<CallRecord> callingInLandRecords = new ArrayList<>();
         List<CallRecord> answerInCityRecords = new ArrayList<>();
         List<CallRecord> answerInProvinceRecords = new ArrayList<>();
         List<CallRecord> answerInLandRecords = new ArrayList<>();
         List<MessageRecord> sendMessageRecords = new ArrayList<>();
         List<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 void addSendMessageRecords(MessageRecord callRecord) {
             sendMessageRecords.add(callRecord);
         }
    
         public void addReceiveMessageRecords(MessageRecord callRecord) {
             receiveMessageRecords.add(callRecord);
         }
    
         public List<CallRecord> getCallingInCityRecords() {
             return callingInCityRecords;
         }
    
         public List<CallRecord> getCallingInLandRecords() {
             return callingInLandRecords;
         }
    
         public List<CallRecord> getCallingInProvinceRecords() {
             return callingInProvinceRecords;
         }
    
         public List<CallRecord> getAnswerInCityRecords() {
             return answerInCityRecords;
         }
    
         public List<CallRecord> getAnswerInLandRecords() {
             return answerInLandRecords;
         }
    
         public List<CallRecord> getAnswerInProvinceRecords() {
             return answerInProvinceRecords;
         }
    
         public List<MessageRecord> getReceiveMessageRecords() {
             return receiveMessageRecords;
         }
    
         public List<MessageRecord> getSendMessageRecords() {
             return sendMessageRecords;
         }
     }
    
    
    
     class telPhoneMessageRule extends CallChargeRule {
    
         @Override
         public double calCost(UserRecords userRecords) {
             double sumCost = 0;
             int number = 0;
             for (MessageRecord m : userRecords.getSendMessageRecords()) {
                 int length = m.getMessage().length();
                 if (length <= 10) {
                     number++;
                 } else {
                     number += length / 10;
                     if (length % 10 != 0) {
                         number++;
                     }
                 }
             }
             if (number <= 3) {
                 sumCost = number * 0.1;
             } else if (number <= 5) {
                 sumCost = 0.3 + 0.2 * (number - 3);
             } else {
                 sumCost = 0.7 + 0.3 * (number - 5);
             }
             return sumCost;
         }
    
     }
    
     class MessageRecord extends CommunicationRecord {
    
         private String message;
    
         public MessageRecord(String input) {
             super();
             this.message = input.substring(26);
         }
    
         public String getMessage() {
             return message;
         }
    
         public void setMessage(String message) {
             this.message = message;
         }
     }
    
    
    
     abstract class CommunicationRecord {
    
         protected String callingNumber;
         protected String answerNumber;
    
         public String getAnswerNumber() {
             return answerNumber;
         }
    
         public void setAnswerNumber(String answerNumber) {
             this.answerNumber = answerNumber;
         }
    
         public String getCallingNumber() {
             return callingNumber;
         }
    
         public void setCallingNumber(String callingNumber) {
             this.callingNumber = callingNumber;
         }
     }
    
     class CallRecord extends CommunicationRecord {
         private Date startTime;
         private Date endTime;
         private String callingAddressAreaCode;
         private String answerAddressAreaCode;
    
         public int getCallType() {
             int type = 0;
             if (callingAddressAreaCode.equals("0791")) {
                 type +=10;
             } else if (callingAddressAreaCode.matches("^079[023456789]$") || callingAddressAreaCode.equals("0701")) {
                 type +=20;
             } else {
                 type +=30;
             }
    
             if (answerAddressAreaCode.equals("0791")) {
                 type +=1;
             } else if (answerAddressAreaCode.matches("^079[023456789]$") || answerAddressAreaCode.equals("0701")) {
                 type +=2;
             } else {
                 type +=3;
             }
             //System.out.println(type/10);
             return type;
    
         }
    
         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 getAnswerAddressAreaCode() {
             return answerAddressAreaCode;
         }
    
         public void setAnswerAddressAreaCode(String answerAddressAreaCode) {
             this.answerAddressAreaCode = answerAddressAreaCode;
         }
    
         public String getCallingAddressAreaCode() {
             return callingAddressAreaCode;
         }
    
         public void setCallingAddressAreaCode(String callingAddressAreaCode) {
             this.callingAddressAreaCode = callingAddressAreaCode;
         }
     }
    
     class telPhoneMessageCharging extends ChargeMode{
    
         private double monthlyRent = 0;
    
         public telPhoneMessageCharging() {
             super();
             chargeRules.add(new telPhoneMessageRule());
         }
    
         @Override
         public double calCost(UserRecords userRecords) {
             double sumCost = 0;
             for (ChargeRule rule : chargeRules) {
                 sumCost += rule.calCost(userRecords);
             }
             return sumCost;
         }
    
         @Override
         public double getMonthlyRent() {
             return monthlyRent;
         }
     }
    
     class telPhoneCharging extends ChargeMode {
    
         private double monthlyRent = 15;
    
         public telPhoneCharging() {
             super();
             chargeRules.add(new telPhoneInCityRule());
             chargeRules.add(new telPhoneInProvinceRule());
             chargeRules.add(new telPhoneInlandRule());
         }
         @Override
         public double calCost(UserRecords userRecords){
             double Sum = 0;
             //System.out.println("?");
             //System.out.println(chargeRules.size());
             for (ChargeRule chargeRule : chargeRules) {
                 Sum += chargeRule.calCost(userRecords);
                 // System.out.println("sum = "+Sum);
             }
             return Sum;
         }
    
         @Override
         public double getMonthlyRent() {
             return monthlyRent;
         }
     }
    
    
     class LandlinePhoneCharging extends ChargeMode {
    
         private double monthlyRent = 20;
         public LandlinePhoneCharging() {
             super();
             chargeRules.add(new LandPhoneInCityRule());
             chargeRules.add(new LandPhoneInProvinceRule());
             chargeRules.add(new LandPhoneInlandRule());
         }
         @Override
         public double calCost(UserRecords userRecords){
             double Sum = 0;
             //System.out.println("?");
             //System.out.println(chargeRules.size());
             for (ChargeRule chargeRule : chargeRules) {
                 Sum += chargeRule.calCost(userRecords);
                 //System.out.println("sum = "+Sum);
             }
             return Sum;
         }
    
         @Override
         public double getMonthlyRent() {
             return monthlyRent;
         }
    
     }
    
     abstract class CallChargeRule extends ChargeRule {
         //abstract public double calCost(List<CallRecord> callRecords);
     }
    
    
     abstract class ChargeRule{
         abstract public double calCost(UserRecords userRecords);
     }
    
     class LandPhoneInCityRule extends CallChargeRule {
    
         @Override
         public double calCost(UserRecords userRecords) {
             double Sum = 0;
             for (CallRecord call : userRecords.getCallingInCityRecords()) {
                 if(call.getCallType() == 11)
                     Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.1;
                 else if(call.getCallType() == 12)
                     Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.3;
                 else if(call.getCallType() == 13)
                     Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.6;
             }
             return Sum;
         }
    
     }
    
     class LandPhoneInProvinceRule extends CallChargeRule {
         @Override
         public double calCost(UserRecords userRecords) {
             double Sum = 0;
             for (CallRecord call : userRecords.getCallingInProvinceRecords()) {
                 Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.3;
             }
             return Sum;
         }
     }
    
     class LandPhoneInlandRule extends CallChargeRule {
         @Override
         public double calCost(UserRecords userRecords) {
             double Sum = 0;
             for (CallRecord call : userRecords.getCallingInLandRecords()) {
                 Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.6;
             }
             return Sum;
         }
     }
    
     class telPhoneInCityRule extends CallChargeRule {
    
         @Override
         public double calCost(UserRecords userRecords) {
             double Sum = 0;
             for (CallRecord call : userRecords.getCallingInCityRecords()) {
                 if(call.getCallType() == 11)
                     Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.1;
                 else if(call.getCallType() == 12)
                     Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.2;
                 else if(call.getCallType() == 13)
                     Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.3;
             }
             return Sum;
         }
    
     }
    
     class telPhoneInProvinceRule extends CallChargeRule {
         @Override
         public double calCost(UserRecords userRecords) {
             double Sum = 0;
             for (CallRecord call : userRecords.getCallingInProvinceRecords()) {
                 Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.3;
             }
             return Sum;
         }
     }
    
     class telPhoneInlandRule extends CallChargeRule {
         @Override
         public double calCost(UserRecords userRecords) {
             double Sum = 0;
             for (CallRecord call : userRecords.getCallingInLandRecords()) {
                 Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.6;
             }
             for (CallRecord call : userRecords.getAnswerInLandRecords()) {
                 Sum += tools.getTime(call.getEndTime(),call.getStartTime())* 0.3;
    
             }
             return Sum;
         }
     }
    
    
     class tools{
    
         public static int checkFormat(String str) {
             if (str.matches("[u]-0791[0-9]{7,8}\\s[0]") || str.matches("[u]-1[0-9]{10}\\s[1]"))
                 return 1;
             else if (str.matches("(([t]-0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s)|"
                     + "([t]-0791[0-9]{7,8}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\s)|"
                     + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "0[0-9]{9,11}\\s)|"
                     + "([t]-1[0-9]{10}\\s" + "0[0-9]{2,3}\\s" + "1[0-9]{10}\\s" + "0[0-9]{2,3}\\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 2;
             }
             return -1;
         }
    
    
         public static int checkMessage(String input) {
             if (input.matches("[u]-0791[0-9]{7,8}\\s[0]") || input.matches("[u]-1[0-9]{10}\\s[13]")) {
                 return 1;
             } else if (input.matches("[m]-1[0-9]{10}\\s" + "1[0-9]{10}\\s" + "[0-9a-zA-Z\\s\\.,]+")) {
                 return 2;
             }
             return 0;
         }
    
    
         public static long getTime(Date endTime,Date startTime){
             long t = (endTime.getTime()-startTime.getTime()) ;
             long time = t / 60000;
             if (t % 60000 != 0) {
                 time += 1;
             }
             return time;
         }
    
     }
    
     class UsersLibrary {
         List<User> userList = new ArrayList<>();
    
         public void addNewUser(String input){
             User user = new User();
             String[] inputs = input.split(" ");
             String tel = inputs[0].substring(2);
             for (User u : userList) {
                 if (u.getNumber().equals(tel)) {
                     return;
                 }
             }
             user.setNumber(tel);
             int mode = Integer.parseInt(inputs[1]);
             if (mode == 0) {
                 user.setChargeMode(new LandlinePhoneCharging());
             } else if (mode == 1) {
                 user.setChargeMode(new telPhoneCharging());
             } else if (mode == 3) {
                 user.setChargeMode(new telPhoneMessageCharging());
             }
             UserRecords userRecords = new UserRecords();
             user.setUserRecords(userRecords);
             userList.add(user);
    
    
         }
    
         public void addNewRecord(String input){
    
             String[] inputs = input.split(" ");
             inputs[0] = inputs[0].substring(2);
    
             User callu = null, answeru = null;
    
             String out = inputs[0];
             String in = "";
             if (inputs.length == 6) {
                 in = inputs[1];
             } else if (inputs.length == 7) {
                 in = inputs[1];
             } else if (inputs.length == 8) {
                 in = inputs[2];
             } else {
                 in = inputs[1];
             }
    
             for (User u : userList) {
                 if (u.getNumber().equals(out)) {
                     callu = u;
                 }
                 if (u.getNumber().equals(in)) {
                     answeru = u;
                 }
                 if (callu != null && answeru != null) {
                     break;
                 }
             }
    
             if (input.charAt(0) == 'm') {
                 MessageRecord messageRecord = new MessageRecord(input);
                 if (callu != null) {
                     callu.getUserRecords().addSendMessageRecords(messageRecord);
                     ;
                 }
                 if (answeru != null) {
                     callu.getUserRecords().addReceiveMessageRecords(messageRecord);
                 }
             }
    
         }
     }
     public class Main {
    
         public static void main(String[] args) {
             Scanner in = new Scanner(System.in);
             UsersLibrary usersLibrary = new UsersLibrary();
             String str = in.nextLine();
             while(!str.equals("end")){
                 //int mode = tools.checkFormat(str);
                 int mode = tools.checkMessage(str);
                 if(mode == 1)
                     usersLibrary.addNewUser(str);
                 else if(mode == 2)
                     usersLibrary.addNewRecord(str);
                 str = in.nextLine();
             }
             usersLibrary.userList.sort(new Comparator<User>() {
    
                 @Override
                 public int compare(User u1, User u2) {
                     if (u1.getNumber().charAt(0) == '0' && u2.getNumber().charAt(0) != '0') {
                         return -1;
                     } else if (u1.getNumber().charAt(0) != '0' && u2.getNumber().charAt(0) == '0') {
                         return 1;
                     }
                     if (Double.parseDouble(u1.getNumber()) > Double.parseDouble(u2.getNumber())) {
                         return 1;
                     } else {
                         return -1;
                     }
                 }
             });
    
             for (User u : usersLibrary.userList) {
                 //System.out.println("  " + u.getUserRecords().callingInLandRecords.size()+"  ");
                 System.out.println(u.getNumber() +" "+ Double.parseDouble(String.format("%.1f",u.calCost())) +" " +
                         Double.parseDouble( String.format("%.1f",u.calBalance()) )  );
             }
    
         }
    
     }
    
  4. SourceMonitor分析

    Kiviat Graph分析
    ①註釋分析:永遠都不想寫註釋捏(大家不要學!!)
    ②每個類中方法數分析:每個類中的方法數也偏少,因為這次把其他的程式碼都刪掉了,就剩了簡訊的方法。
    ③每個方法中有效程式碼行數分析:每個方法中有效行數也比較少,大量的get和set方法拉低平均值。
    ④最大圈複雜度分析:最大圈複雜度比較的高,有些程式碼直接寫在了main裡面了,所以一般不要在main裡面放實現的程式碼。
    ⑤最大深度分析:最大深度比較合適,其實這幾個題目集都還比較好,我認為這也反映了類的結構其實設計的不錯。
    ⑥平均深度分析:平均深度還可以接收,同上~~~
    ⑦平均圈複雜度分析:平均複雜度很低,因為就只寫了一個簡訊的處理,比之前的手機+座機還要低。

    Block Histogram分析
    仍舊是處在1-3的居多,比起多邊形的題庫,整體的深度都有下降,也側證了我說的,計算部分比較簡單,不像多邊形那樣調來調去。

三、踩坑心得

  1. 正則表示式(沒錯,又雙叒叕是它)

    正則之前一直想著是寫一行總的格式進行判定,然後過不去之後,修修改改,把各種能想到的限制條件都加上去了,包括
    長度啊,手機號開頭的數字,時間等等,還是過不去AWA,然後開始擺爛了,把所有的情況列舉出來,用好多個不同的正則
    或運算,然後才過的。

  2. 程式碼卡時間

    可能我的理解沒有那麼的深刻,照著類圖上構造之後,寫出來的程式碼居然會超時......我真的很無語,題目限制了執行時間
    400ms,而我的大部分過了的測試點也在390ms左右,只能說寫的可能太繞了,最最主要是,每次提交過的點還不一樣,因為
    有可能上一次執行超時了,這一次又在400ms內執行完成了,無語嘞......

四、改進意見

  1. 程式碼結構還可以再優化一下,包括對輸入資料處理的那一段,我感覺超時大概率是因為在處理使用者通話資料的時候,兩重迴圈
    導致時間過多了QWQ,不好評價好吧。至於優化方法,可以在讀入每條資料的時候就將它插入到使用者裡去。而不是把所有資料
    放在一個列表裡後,再用兩重迴圈來把列表中的所有通話記錄插入到對應使用者的記錄中去。

  2. 這次倒是根據老師給出的類圖構建程式碼,做到了屬性私有化,但是get和set方法在一個類中佔據了大半,剩下的處理方法就幾個了,
    還包括了建構函式。

五、總結

總得來說,相對於多邊形的題目,還是要簡單一些的,主要的問題都是在類的構建上
但之前也說過了,通過老師給的類圖,還是能保證類的複雜度沒有那麼高,至少老師給的部分沒有qwq
比如說超時問題,大概率是我後面補充的類的構造不是很合理,倒是增加了時間複雜度了。
因此,對於整個類的結構的理解還是有所欠缺,當然還是對類的構造又了新的理解。
原本我是想要將收費放在通話記錄中的,這樣每個通話記錄之間呼叫cost函式,就可以得出這條通話記錄的費用
但是轉念一想,老師給的類圖這樣做確實很合理,通話記錄做的應該只是記錄通話的相關資訊,而計費是通話後的結果
應該構建一個計費類,傳引數為通話記錄,然後通過計費類來計算似乎更加合理一些。
好了,不囉嗦了,Over~~