一.前言
题目集六:
本次大作业是第一次写电信计费,难度较前几次的多边形有了明显的下降,题目难点不再是算法的设计,而是类与类之间关系的设计,同样也是因为第一次写电信计费,刚开始的工作量确实很大,不过还好这一次题目集的题量不是很多,整体而言没有前几次作业的压力大
题目集七:
电信计费系列二是在系列一上面添加了手机的计费规则,考察问题的核心还是我们对于类之间关系的掌握情况。不过好在这两次作业是分割开的,有了第一次实验代码的基础,添加手机的计费规则只需要对原来的代码进行修改就可以了,难度不大,主要问题还是时间格式的判断问题。
题目集八:
电信计费系列三是有另外添加了短信的计费规则,不过在这次作业中甚至没有手机和座机之间电话的计算,这就变得更加简单了,不过同样的也多出了许多的问题,比如短信格式的判断等。
二.设计与分析
题目一:
实现一个简单的电信计费程序:
假设南昌市电信分公司针对市内座机用户采用的计费方式:
月租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 import java.util.ArrayList; 2 import java.text.ParseException; 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.Scanner; 6 class Main { 7 public static void main(String[] arges) { 8 Scanner input = new Scanner(System.in); 9 String date = input.nextLine(); 10 FormatTest f = new FormatTest(date); 11 Tools t = new Tools(); 12 ArrayList<User> user = new ArrayList<User>(); 13 while (!date.equals("end")) { 14 // System.out.print(t.isFromat()+"\n"); 15 if (f.isFromat()) { 16 if (f.getType() == 'u') 17 t.setUser(f, user); 18 else 19 t.setInfo(f, user); 20 } 21 date = input.nextLine(); 22 f = new FormatTest(date); 23 } 24 user = t.OrderUser(user); 25 for (int i = 0; i < user.size(); i++) { 26 System.out.print(user.get(i).getNumber()+" "); 27 t.FormatOut(user.get(i).calCost()); 28 System.out.print(" "); 29 t.FormatOut(user.get(i).calBalance()); 30 System.out.print("\n"); 31 } 32 } 33 } 34 abstract class CallChargeRule extends ChargeRules{ 35 36 public abstract double calCost(ArrayList<CallRecord> callRecords); 37 } 38 class CallRecord extends CommunicationRecord { 39 private Date startTime; 40 private Date endTime; 41 private String callingAddressAreaCode; 42 private String answerAddressAreaCode; 43 public Date getStartTime() { 44 return startTime; 45 } 46 47 public void setStartTime(Date startTime) { 48 this.startTime = startTime; 49 } 50 51 public Date getendTime() { 52 return endTime; 53 } 54 55 public void setendTime(Date endTime) { 56 this.endTime = endTime; 57 } 58 59 public String getCallingAddressAreaCode() { 60 return callingAddressAreaCode; 61 } 62 63 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 64 this.callingAddressAreaCode = callingAddressAreaCode; 65 } 66 67 public String getAnswerAddressAreaCode() { 68 return answerAddressAreaCode; 69 } 70 71 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 72 this.answerAddressAreaCode = answerAddressAreaCode; 73 } 74 75 } 76 abstract class ChargeMode { 77 protected ArrayList<ChargeRules> chargeRules = new ArrayList<>(); 78 79 public ArrayList<ChargeRules> getChargeRules() { 80 return chargeRules; 81 } 82 83 public void setChargeRules(ArrayList<ChargeRules> chargeRules) { 84 this.chargeRules = chargeRules; 85 } 86 public abstract double calCost(UserRecords userRecords); 87 public abstract double getMonthlyRent(); 88 } 89 abstract class ChargeRules { 90 91 } 92 abstract class CommunicationRecord { 93 protected String callingNumber; 94 protected String answerNumber; 95 public String getCallingNumber() { 96 return callingNumber; 97 } 98 public void setCallingNumber(String callingNumber) { 99 this.callingNumber = callingNumber; 100 } 101 public String getAnswerNumber() { 102 return answerNumber; 103 } 104 public void setAnswerNumber(String answerNumber) { 105 this.answerNumber = answerNumber; 106 } 107 } 108 class FormatTest { 109 String s; 110 SimpleDateFormat Format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); 111 112 FormatTest(String s) { 113 this.s = s; 114 } 115 116 public boolean isTimeFormat(String date) throws ParseException { 117 118 Format.parse(date); 119 120 String forhead = date.split(" ")[0]; 121 String behind = date.split(" ")[1]; 122 int year = Integer.parseInt(forhead.split("\\.")[0]); 123 int month = Integer.parseInt(forhead.split("\\.")[1]); 124 int day = Integer.parseInt(forhead.split("\\.")[2]); 125 int hours = Integer.parseInt(behind.split(":")[0]); 126 int minute = Integer.parseInt(behind.split(":")[1]); 127 int second = Integer.parseInt(behind.split(":")[2]); 128 if (month < 0 || month > 12) 129 return false; 130 int[] monthLengths = new int[] { 0, 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 131 if (isLeapYear(year)) { 132 monthLengths[2] = 29; 133 } else { 134 monthLengths[2] = 28; 135 } 136 int monthLength = monthLengths[month]; 137 if (day < 1 || day > monthLength) { 138 return false; 139 } 140 if (hours < 0 || hours > 23) 141 return false; 142 if (second < 0 || second > 59) 143 return false; 144 if (minute < 0 || minute > 59) 145 return false; 146 return true; 147 148 } 149 150 private boolean isLeapYear(int year) { 151 return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); 152 } 153 154 public String getUserNumber() { 155 return s.substring(2).split(" ")[0]; 156 157 } 158 159 public String getCallingAreaCode() { 160 return s.substring(2).split(" ")[0].substring(0, 4); 161 162 } 163 164 public String getAnswerAreaCode() { 165 return s.substring(2).split(" ")[1].substring(0, 4); 166 167 } 168 169 public String getCallingNumber() { 170 return s.substring(2).split(" ")[0]; 171 172 } 173 174 public String getAnswerNumber() { 175 return s.substring(2).split(" ")[1]; 176 177 } 178 179 public String getUserMode() { 180 return s.substring(2).split(" ")[1]; 181 182 } 183 184 public Date getstartTime() { 185 Date startTime = null; 186 String detail[]; 187 detail = s.substring(2).split(" "); 188 String StartTime = detail[2].concat(" " + detail[3]); 189 try { 190 startTime = Format.parse(StartTime); 191 } catch (ParseException e) { 192 193 e.printStackTrace(); 194 } 195 return startTime; 196 } 197 198 public Date getendTime() { 199 Date endTime = null; 200 String detail[]; 201 detail = s.substring(2).split(" "); 202 String EndTime = detail[4].concat(" " + detail[5]); 203 try { 204 endTime = Format.parse(EndTime); 205 } catch (ParseException e) { 206 207 e.printStackTrace(); 208 } 209 return endTime; 210 211 } 212 213 public char getType() { 214 return s.charAt(0); 215 } 216 217 public boolean isFromat() { 218 try { 219 char type = s.charAt(0); 220 if (type == 'u') { 221 return AccountFormat(); 222 } else if (type == 't') { 223 return InfoFormat(); 224 } else 225 return false; 226 } catch (Exception e) { 227 return false; 228 } 229 } 230 231 private boolean InfoFormat() throws ParseException { 232 String tPattern = "t-\\d{10,12}\\s" + "\\d{10,12}\\s" + 233 "([1-9][0-9]*\\.[1-9][0-9]?\\.[1-9][0-9]? ([0|1]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] ?){2}"; 234 if(s.matches(tPattern)) 235 return true; 236 else 237 return false; 238 /*String detail[]; 239 detail = s.substring(2).split(" "); 240 if(detail.length!=6) 241 return false; 242 String StartTime = detail[2].concat(" " + detail[3]); 243 String EndTime = detail[4].concat(" " + detail[5]); 244 if (!isCallFormat(detail[0])) 245 return false; 246 if (!isCallFormat(detail[1])) 247 return false; 248 if (!isTimeFormat(StartTime)) 249 return false; 250 if (!isTimeFormat(EndTime)) 251 return false; 252 if (!isIntervalFormat(StartTime, EndTime)) 253 return false; 254 return true;*/ 255 256 } 257 258 private boolean isIntervalFormat(String startTime, String endTime) throws ParseException { 259 Date start = null; 260 Date end = null; 261 262 start = Format.parse(startTime); 263 264 end = Format.parse(endTime); 265 266 Long interval = (end.getTime() - start.getTime()) / 1000; 267 if (interval < 0) 268 return false; 269 else 270 return true; 271 272 } 273 274 private boolean AccountFormat() { 275 String uPattern = "u-\\d{10,12}\\s[0-2]"; 276 if(!s.matches(uPattern)) 277 return false; 278 else 279 return true; 280 /*String detail[]; 281 detail = s.substring(2).split(" "); 282 if(detail.length!=2) 283 return false; 284 String Call = detail[0]; 285 String Type = detail[1]; 286 if (!isCallFormat(Call)) 287 return false; 288 if (!Type.matches("[012]")) 289 return false; 290 return true;*/ 291 292 } 293 294 private boolean isCallFormat(String call) { 295 return call.matches("0791[0-9]{7,8}\\s" + "0[0-9]{9,11}\\s"); 296 } 297 } 298 299 300 301 class LandlinePhoneCharging extends ChargeMode{ 302 private double monthlyRent=20; 303 public LandlinePhoneCharging() { 304 305 /*super(); 306 chargeRules.add(new LandPhoneInCityRule()); 307 chargeRules.add(new LandPhoneInProvinceRule()); 308 chargeRules.add(new LandPhoneInLandRule());*/ 309 } 310 @Override 311 public double calCost(UserRecords userRecords) { 312 ArrayList<CallRecord> InCitycallRecords =new ArrayList<CallRecord>(); 313 ArrayList<CallRecord> InProvincecallRecords =new ArrayList<CallRecord>(); 314 ArrayList<CallRecord> InLandcallRecords =new ArrayList<CallRecord>(); 315 CallChargeRule InCityCharge = new LandPhoneInCityRule(); 316 CallChargeRule InProvinceCharge = new LandPhoneInProvinceRule(); 317 CallChargeRule InLandCharge = new LandPhoneInLandRule(); 318 for(int i=0;i<userRecords.getCallingInCityRecords().size();i++) 319 InCitycallRecords.add(userRecords.getCallingInCityRecords().get(i)); 320 for(int i=0;i<userRecords.getCallingInProvinceRecords().size();i++) 321 InProvincecallRecords.add(userRecords.getCallingInProvinceRecords().get(i)); 322 for(int i=0;i<userRecords.getCallingInLandRecords().size();i++) 323 InLandcallRecords.add(userRecords.getCallingInLandRecords().get(i)); 324 return InCityCharge.calCost(InCitycallRecords)+InProvinceCharge.calCost(InProvincecallRecords)+InLandCharge.calCost(InLandcallRecords); 325 } 326 327 @Override 328 public double getMonthlyRent() { 329 // TODO 自动生成的方法存根 330 return monthlyRent; 331 } 332 333 public void setMonthlyRent(double monthlyRent) { 334 this.monthlyRent = monthlyRent; 335 } 336 337 } 338 class LandPhoneInCityRule extends CallChargeRule{ 339 long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数 340 long nh = 1000 * 60 * 60;// 一小时的毫秒数 341 long nm = 1000 * 60;// 一分钟的毫秒数 342 long ns = 1000;// 一秒钟的毫秒数 343 @Override 344 public double calCost(ArrayList<CallRecord> callRecords) { 345 double sum=0; 346 for(int i=0;i<callRecords.size();i++) { 347 Date startTime=callRecords.get(i).getStartTime(); 348 Date endTime=callRecords.get(i).getendTime(); 349 Long interval = (endTime.getTime() - startTime.getTime())/1000; 350 if(interval%60!=0) 351 interval=(interval/60)+1; 352 else 353 interval=interval/60; 354 sum=sum+interval*0.1; 355 } 356 return sum; 357 } 358 359 } 360 class LandPhoneInLandRule extends CallChargeRule{ 361 long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数 362 long nh = 1000 * 60 * 60;// 一小时的毫秒数 363 long nm = 1000 * 60;// 一分钟的毫秒数 364 long ns = 1000;// 一秒钟的毫秒数 365 @Override 366 public double calCost(ArrayList<CallRecord> callRecords) { 367 double sum=0; 368 for(int i=0;i<callRecords.size();i++) { 369 Date startTime=callRecords.get(i).getStartTime(); 370 Date endTime=callRecords.get(i).getendTime(); 371 Long interval = (endTime.getTime() - startTime.getTime())/1000; 372 if(interval%60!=0) 373 interval=(interval/60)+1; 374 else 375 interval=interval/60; 376 sum=sum+interval*0.6; 377 } 378 return sum; 379 } 380 381 } 382 class LandPhoneInProvinceRule extends CallChargeRule{ 383 long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数 384 long nh = 1000 * 60 * 60;// 一小时的毫秒数 385 long nm = 1000 * 60;// 一分钟的毫秒数 386 long ns = 1000;// 一秒钟的毫秒数 387 @Override 388 public double calCost(ArrayList<CallRecord> callRecords) { 389 double sum=0; 390 for(int i=0;i<callRecords.size();i++) { 391 Date startTime=callRecords.get(i).getStartTime(); 392 Date endTime=callRecords.get(i).getendTime(); 393 Long interval = (endTime.getTime() - startTime.getTime())/1000; 394 if(interval%60!=0) 395 interval=(interval/60)+1; 396 else 397 interval=interval/60; 398 sum=sum+interval*0.3; 399 } 400 return sum; 401 } 402 403 } 404 class MessageRecord { 405 private String message; 406 407 public String getMessage() { 408 return message; 409 } 410 411 public void setMessage(String message) { 412 this.message = message; 413 } 414 415 } 416 class Tools { 417 public void setInfo(FormatTest f, ArrayList<User> user) { 418 int call; 419 call=this.isAccounted(f.getCallingNumber(),user); 420 if(call!=-1) { 421 CallRecord record=new CallRecord(); 422 record.setAnswerAddressAreaCode(f.getAnswerAreaCode()); 423 record.setCallingAddressAreaCode(f.getCallingAreaCode()); 424 record.setAnswerNumber(f.getAnswerNumber()); 425 record.setCallingNumber(f.getCallingNumber()); 426 record.setStartTime(f.getstartTime()); 427 record.setendTime(f.getendTime()); 428 user.get(call).setUserRecords(record); 429 } 430 } 431 432 public void setUser(FormatTest t, ArrayList<User> user) { 433 User u = new User(); 434 if (isAccounted(t.getUserNumber(), user) == -1) { 435 u.setNumber(t.getUserNumber()); 436 if (t.getUserMode().matches("0")) 437 u.setChargeMode(new LandlinePhoneCharging()); 438 user.add(u); 439 } 440 } 441 public void setUserChargeMode(FormatTest t, ArrayList<User> user) { 442 User u = new User(); 443 u.setNumber(t.getUserNumber()); 444 user.add(u); 445 } 446 public int isAccounted(String num,ArrayList<User> user) { 447 for(int i=0;i<user.size();i++) 448 if(user.get(i).getNumber().equals(num)) 449 return i; 450 return -1; 451 } 452 public void FormatOut(double x) { 453 if ((x * 1e1) % 10 != 0) 454 System.out.printf("%.1f", x); 455 else 456 System.out.print(x); 457 } 458 public ArrayList<User> OrderUser(ArrayList<User> user){ 459 ArrayList<User> u = new ArrayList<User>(); 460 int index=0; 461 while (user.size()!=0){ 462 { 463 index=0; 464 for(int j=0;j<user.size();j++) 465 { 466 if(user.get(j).getNumber().compareTo(user.get(index).getNumber())<0) 467 index=j; 468 } 469 u.add(user.get(index)); 470 user.remove(index); 471 } 472 } 473 return u; 474 } 475 } 476 class User { 477 private UserRecords userRecords = new UserRecords(); 478 private double balance = 100; 479 private ChargeMode chargeMode; 480 private String number; 481 482 public double calBalance() { 483 return balance-this.calCost()-this.chargeMode.getMonthlyRent(); 484 } 485 486 public double calCost() { 487 return this.chargeMode.calCost(userRecords); 488 489 } 490 491 public UserRecords getUserRecords() { 492 return userRecords; 493 } 494 495 public void setUserRecords(CallRecord record) { 496 if(record.getAnswerAddressAreaCode().equals("0791")) 497 this.userRecords.addCallingInCityRecords(record); 498 else if(record.getAnswerAddressAreaCode().matches("079\\d||0701")) 499 this.userRecords.addCallingInProvinceRecords(record); 500 else 501 this.userRecords.addCallingInLandRecords(record); 502 } 503 504 public double getBalance() { 505 return balance; 506 } 507 508 public ChargeMode getChargeMode() { 509 return chargeMode; 510 } 511 512 public void setChargeMode(ChargeMode chargeMode) { 513 this.chargeMode = chargeMode; 514 } 515 516 public String getNumber() { 517 return number; 518 } 519 520 public void setNumber(String number) { 521 this.number = number; 522 } 523 } 524 class UserRecords { 525 private ArrayList<CallRecord> callingInCityRecords =new ArrayList<CallRecord>(); 526 private ArrayList<CallRecord> callingInProvinceRecords =new ArrayList<CallRecord>(); 527 private ArrayList<CallRecord> callingInLandRecords =new ArrayList<CallRecord>(); 528 private ArrayList<CallRecord> answerInCityRecords =new ArrayList<CallRecord>(); 529 private ArrayList<CallRecord> answerInProvinceRecords =new ArrayList<CallRecord>(); 530 private ArrayList<CallRecord> answerInLandRecords =new ArrayList<CallRecord>(); 531 private ArrayList<MessageRecord> sendMessageRecords =new ArrayList<MessageRecord>(); 532 private ArrayList<MessageRecord> receiveMessageRecords =new ArrayList<MessageRecord>(); 533 534 public ArrayList<CallRecord> getCallingInCityRecords() { 535 return callingInCityRecords; 536 } 537 538 public void addCallingInCityRecords(CallRecord callingInCityRecords) { 539 this.callingInCityRecords.add(callingInCityRecords); 540 } 541 542 public ArrayList<CallRecord> getAnswerInCityRecords() { 543 return answerInCityRecords; 544 } 545 546 public void addAnswerInCityRecords(CallRecord answerInCityRecords) { 547 this.answerInCityRecords.add(answerInCityRecords); 548 } 549 550 public ArrayList<CallRecord> getCallingInProvinceRecords() { 551 return callingInProvinceRecords; 552 } 553 554 public void addCallingInProvinceRecords(CallRecord callingInProvinceRecords) { 555 this.callingInProvinceRecords.add(callingInProvinceRecords); 556 } 557 558 public ArrayList<CallRecord> getCallingInLandRecords() { 559 return callingInLandRecords; 560 } 561 562 public void addCallingInLandRecords(CallRecord callingInLandRecords) { 563 this.callingInLandRecords.add(callingInLandRecords); 564 } 565 566 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 567 return answerInProvinceRecords; 568 } 569 570 public void addAnswerInProvinceRecords(CallRecord answerInProvinceRecords) { 571 this.answerInProvinceRecords.add(answerInProvinceRecords); 572 } 573 574 public ArrayList<CallRecord> getAnswerInLandRecords() { 575 return answerInLandRecords; 576 } 577 578 public void addAnswerInLandRecords(CallRecord answerInLandRecords) { 579 this.answerInLandRecords.add(answerInLandRecords); 580 } 581 582 public ArrayList<MessageRecord> getSendMessageRecords() { 583 return sendMessageRecords; 584 } 585 586 public void addSendMessageRecords(MessageRecord sendMessageRecords) { 587 this.sendMessageRecords.add(sendMessageRecords); 588 } 589 590 public ArrayList<MessageRecord> getReceiveMessageRecords() { 591 return receiveMessageRecords; 592 } 593 594 public void addReceiveMessageRecords(MessageRecord receiveMessageRecords) { 595 this.receiveMessageRecords.add(receiveMessageRecords); 596 } 597 598 }View Code
类图设计是在题目中就提供了一个参考,这也正是本题的难点,虽说是提供了参考,但是我们目前的能力也只能比着题目里的类图来进行写代码,看懂类图并且如何运用提供的类图写代码便成为了这道题目最难的点。题目算法较为简单,圈复杂度与代码深度都处于一个合理的范围。
题目二:
实现南昌市电信分公司的计费程序,假设该公司针对手机和座机用户分别采取了两种计费方案,分别如下:
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元。
每条通讯、短信信息均单独计费后累加,不是将所有信息累计后统一计费。
格式:号码+英文空格符+总的话费+英文空格符+余额
每个用户一行,用户之间按号码字符从小到大排序。
错误处理:
输入数据中出现的不符合格式要求的行一律忽略。
1 import java.util.ArrayList; 2 import java.text.ParseException; 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.Scanner; 6 7 class Main { 8 public static void main(String[] arges) { 9 Scanner input = new Scanner(System.in); 10 String data = input.nextLine(); 11 Format f = new Format(data); 12 Tools t = new Tools(); 13 ArrayList<User> user = new ArrayList<User>(); 14 while (!data.equals("end")) { 15 if (f.isFromat()) { 16 if (f.getType() == 'u') 17 t.setUser(f, user); 18 else 19 t.setInfo(f, user); 20 } 21 data = input.nextLine(); 22 f = new Format(data); 23 } 24 user = t.OrderUser(user); 25 for (int i = 0; i < user.size(); i++) { 26 System.out.print(user.get(i).getNumber()+" "); 27 System.out.print(String.format("%.1f", user.get(i).calCost())); 28 //t.FormatOut(user.get(i).calCost()); 29 System.out.print(" "); 30 // t.FormatOut(user.get(i).calBalance()); 31 System.out.print(String.format("%.1f", user.get(i).calBalance())); 32 System.out.print("\n"); 33 } 34 input.close(); 35 } 36 37 } 38 abstract class CallChargeRule extends ChargeRules{ 39 public abstract double calCost(ArrayList<CallRecord> callRecords); 40 } 41 class CallRecord extends CommunicationRecord { 42 private Date startTime; 43 private Date endTime; 44 private String callingAddressAreaCode; 45 private String answerAddressAreaCode; 46 public Date getStartTime() { 47 return startTime; 48 } 49 50 public void setStartTime(Date startTime) { 51 this.startTime = startTime; 52 } 53 54 public Date getendTime() { 55 return endTime; 56 } 57 58 public void setendTime(Date endTime) { 59 this.endTime = endTime; 60 } 61 62 public String getCallingAddressAreaCode() { 63 return callingAddressAreaCode; 64 } 65 66 public void setCallingAddressAreaCode(String callingAddressAreaCode) { 67 this.callingAddressAreaCode = callingAddressAreaCode; 68 } 69 70 public String getAnswerAddressAreaCode() { 71 return answerAddressAreaCode; 72 } 73 74 public void setAnswerAddressAreaCode(String answerAddressAreaCode) { 75 this.answerAddressAreaCode = answerAddressAreaCode; 76 } 77 78 } 79 abstract class ChargeMode { 80 protected ArrayList<CallChargeRule> chargeRules = new ArrayList<>(); 81 82 83 public abstract double calCost(UserRecords userRecords); 84 public abstract double getMonthlyRent(); 85 } 86 abstract class ChargeRules { 87 88 } 89 abstract class CommunicationRecord { 90 protected String callingNumber; 91 protected String answerNumber; 92 public String getCallingNumber() { 93 return callingNumber; 94 } 95 public void setCallingNumber(String callingNumber) { 96 this.callingNumber = callingNumber; 97 } 98 public String getAnswerNumber() { 99 return answerNumber; 100 } 101 public void setAnswerNumber(String answerNumber) { 102 this.answerNumber = answerNumber; 103 } 104 } 105 class Format { 106 String s; 107 SimpleDateFormat Format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); 108 109 Format(String s) { 110 this.s = s; 111 } 112 113 public String getInfo(int n) { 114 return s.substring(2).split(" ")[n]; 115 116 } 117 118 public String getUserNumber() { 119 return s.substring(2).split(" ")[0]; 120 121 } 122 123 public String getUserMode() { 124 return s.substring(2).split(" ")[1]; 125 126 } 127 128 public Date getstartTime(int n) { 129 Date startTime = null; 130 String detail[]; 131 detail = s.substring(n).split(" "); 132 String StartTime = detail[n].concat(" " + detail[n + 1]); 133 try { 134 startTime = Format.parse(StartTime); 135 } catch (ParseException e) { 136 137 e.printStackTrace(); 138 } 139 return startTime; 140 } 141 142 public Date getendTime(int n) { 143 Date endTime = null; 144 String detail[]; 145 detail = s.substring(2).split(" "); 146 String EndTime = detail[n + 2].concat(" " + detail[n + 3]); 147 try { 148 endTime = Format.parse(EndTime); 149 } catch (ParseException e) { 150 151 e.printStackTrace(); 152 } 153 return endTime; 154 155 } 156 157 public char getType() { 158 return s.charAt(0); 159 } 160 161 public boolean isFromat() { 162 if(s.equals("")) 163 return false; 164 char type = s.charAt(0); 165 if (type == 'u') { 166 return AccountFormat(); 167 } else if (type == 't') { 168 return InfoFormat(); 169 } else 170 return false; 171 } 172 173 private boolean InfoFormat() { 174 String tPattern = "t-0\\d{9,11}\\s" + "0\\d{9,11}\\s" 175 + "([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3}\\.(1[0-2]|[1-9])\\.([1-9]|(1|2)[0-9]|(30|31)) ([0|1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] ?){2}"; 176 String tPattern1 = "t-\\d{11}\\s\\d{3,4}\\s" + "\\d{11}\\s\\d{3,4}\\s" 177 + "([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3}\\.(1[0-2]|[1-9])\\.([1-9]|(1|2)[0-9]|(30|31)) ([0|1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] ?){2}"; 178 String tPattern2 = "t-\\d{11}\\s\\d{3,4}\\s" + "\\d{10,12}\\s" 179 + "([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3}\\.(1[0-2]|[1-9])\\.([1-9]|(1|2)[0-9]|(30|31)) ([0|1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] ?){2}"; 180 String tPattern3 = "t-\\d{10,12}\\s" + "1\\d{10}\\s\\d{3,4}\\s" 181 + "([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3}\\.(1[0-2]|[1-9])\\.([1-9]|(1|2)[0-9]|(30|31)) ([0|1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] ?){2}"; 182 if (s.matches(tPattern) || s.matches(tPattern1) || s.matches(tPattern2) || s.matches(tPattern3)) 183 return true; 184 else 185 return false; 186 } 187 188 private boolean AccountFormat() { 189 String uPattern = "u-\\d{10,12}\\s[0-2]"; 190 String uPattern1 = "u-\\d{11}\\s[0-2]"; 191 if (s.matches(uPattern) ) 192 return true; 193 else 194 return false; 195 196 } 197 198 199 } 200 class LandlinePhoneCharging extends ChargeMode{ 201 private double monthlyRent=20; 202 public LandlinePhoneCharging() { 203 super(); 204 chargeRules.add(new LandPhoneInCityRule()); 205 chargeRules.add(new LandPhoneInProvinceRule()); 206 chargeRules.add(new LandPhoneInLandRule()); 207 } 208 @Override 209 public double calCost(UserRecords userRecords) { 210 double sum=0; 211 for(CallChargeRule e:this.chargeRules) { 212 if(e instanceof LandPhoneInCityRule) 213 sum+=e.calCost(userRecords.getCallingInCityRecords()); 214 else if(e instanceof LandPhoneInProvinceRule) 215 sum+=e.calCost(userRecords.getCallingInProvinceRecords()); 216 else 217 sum+=e.calCost(userRecords.getCallingInLandRecords()); 218 } 219 return sum; 220 } 221 222 @Override 223 public double getMonthlyRent() { 224 // TODO 自动生成的方法存根 225 return monthlyRent; 226 } 227 228 public void setMonthlyRent(double monthlyRent) { 229 this.monthlyRent = monthlyRent; 230 } 231 232 } 233 class LandPhoneInCityRule extends CallChargeRule{ 234 @Override 235 public double calCost(ArrayList<CallRecord> callRecords) { 236 double sum=0; 237 for(int i=0;i<callRecords.size();i++) { 238 Date startTime=callRecords.get(i).getStartTime(); 239 Date endTime=callRecords.get(i).getendTime(); 240 Long interval = (endTime.getTime() - startTime.getTime())/1000; 241 if(interval%60!=0) 242 interval=(interval/60)+1; 243 else 244 interval=interval/60; 245 if(callRecords.get(i).getAnswerAddressAreaCode().matches("0791")) 246 sum=sum+interval*0.1; 247 else if(callRecords.get(i).getAnswerAddressAreaCode().matches("079\\d||0701")) 248 sum=sum+interval*0.3; 249 else 250 sum=sum+interval*0.6; 251 } 252 return sum; 253 } 254 } 255 class LandPhoneInLandRule extends CallChargeRule{ 256 @Override 257 public double calCost(ArrayList<CallRecord> callRecords) { 258 double sum=0; 259 for(int i=0;i<callRecords.size();i++) { 260 Date startTime=callRecords.get(i).getStartTime(); 261 Date endTime=callRecords.get(i).getendTime(); 262 Long interval = (endTime.getTime() - startTime.getTime())/1000; 263 if(interval%60!=0) 264 interval=(interval/60)+1; 265 else 266 interval=interval/60; 267 sum=sum+interval*0.6; 268 } 269 return sum; 270 } 271 272 } 273 class LandPhoneInProvinceRule extends CallChargeRule{ 274 long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数 275 long nh = 1000 * 60 * 60;// 一小时的毫秒数 276 long nm = 1000 * 60;// 一分钟的毫秒数 277 long ns = 1000;// 一秒钟的毫秒数 278 @Override 279 public double calCost(ArrayList<CallRecord> callRecords) { 280 double sum=0; 281 for(int i=0;i<callRecords.size();i++) { 282 Date startTime=callRecords.get(i).getStartTime(); 283 Date endTime=callRecords.get(i).getendTime(); 284 Long interval = (endTime.getTime() - startTime.getTime())/1000; 285 if(interval%60!=0) 286 interval=(interval/60)+1; 287 else 288 interval=interval/60; 289 sum=sum+interval*0.3; 290 } 291 return sum; 292 } 293 294 } 295 class MessageRecord { 296 private String message; 297 298 public String getMessage() { 299 return message; 300 } 301 302 public void setMessage(String message) { 303 this.message = message; 304 } 305 306 } 307 class MobilePhoneAnswer extends CallChargeRule{ 308 309 @Override 310 public double calCost(ArrayList<CallRecord> answerRecords) { 311 double sum=0; 312 for(int i=0;i<answerRecords.size();i++) { 313 Date startTime=answerRecords.get(i).getStartTime(); 314 Date endTime=answerRecords.get(i).getendTime(); 315 Long interval = (endTime.getTime() - startTime.getTime())/1000; 316 if(interval%60!=0) 317 interval=(interval/60)+1; 318 else 319 interval=interval/60; 320 sum=sum+interval*0.3; 321 } 322 return sum; 323 } 324 325 } 326 class MobilePhoneCharging extends ChargeMode{ 327 private double monthlyRent=15; 328 public MobilePhoneCharging() { 329 super(); 330 chargeRules.add(new MobilePhoneAnswer ()); 331 chargeRules.add(new MobilePhoneInCity ()); 332 chargeRules.add(new MobilePhoneInLand ()); 333 chargeRules.add(new MobilePhoneInProvince ()); 334 } 335 336 @Override 337 public double calCost(UserRecords userRecords) { 338 double sum=0; 339 for(CallChargeRule e:this.chargeRules) { 340 if(e instanceof MobilePhoneAnswer) 341 sum+=e.calCost(userRecords.getAnswerInLandRecords()); 342 else if(e instanceof MobilePhoneInCity) 343 sum+=e.calCost(userRecords.getCallingInCityRecords()); 344 else if(e instanceof MobilePhoneInLand) 345 sum+=e.calCost(userRecords.getCallingInLandRecords()); 346 else 347 sum+=e.calCost(userRecords.getCallingInProvinceRecords()); 348 } 349 return sum; 350 } 351 352 @Override 353 public double getMonthlyRent() { 354 // TODO 自动生成的方法存根 355 return monthlyRent; 356 } 357 358 public void setMonthlyRent(double monthlyRent) { 359 this.monthlyRent = monthlyRent; 360 } 361 362 } 363 class MobilePhoneInCity extends CallChargeRule{ 364 365 @Override 366 public double calCost(ArrayList<CallRecord> callRecords) { 367 double sum=0; 368 for(int i=0;i<callRecords.size();i++) { 369 Date startTime=callRecords.get(i).getStartTime(); 370 Date endTime=callRecords.get(i).getendTime(); 371 Long interval = (endTime.getTime() - startTime.getTime())/1000; 372 if(interval%60!=0) 373 interval=(interval/60)+1; 374 else 375 interval=interval/60; 376 if(callRecords.get(i).getAnswerAddressAreaCode().matches("0791")) 377 sum=sum+interval*0.1; 378 else if(callRecords.get(i).getAnswerAddressAreaCode().matches("079\\d||0701")) 379 sum=sum+interval*0.2; 380 else 381 sum=sum+interval*0.3; 382 } 383 return sum; 384 } 385 386 } 387 class MobilePhoneInLand extends CallChargeRule{ 388 389 @Override 390 public double calCost(ArrayList<CallRecord> callRecords) { 391 double sum=0; 392 for(int i=0;i<callRecords.size();i++) { 393 Date startTime=callRecords.get(i).getStartTime(); 394 Date endTime=callRecords.get(i).getendTime(); 395 Long interval = (endTime.getTime() - startTime.getTime())/1000; 396 if(interval%60!=0) 397 interval=(interval/60)+1; 398 else 399 interval=interval/60; 400 sum=sum+interval*0.6; 401 } 402 return sum; 403 } 404 405 406 } 407 class MobilePhoneInProvince extends CallChargeRule{ 408 409 @Override 410 public double calCost(ArrayList<CallRecord> callRecords) { 411 double sum=0; 412 for(int i=0;i<callRecords.size();i++) { 413 Date startTime=callRecords.get(i).getStartTime(); 414 Date endTime=callRecords.get(i).getendTime(); 415 Long interval = (endTime.getTime() - startTime.getTime())/1000; 416 if(interval%60!=0) 417 interval=(interval/60)+1; 418 else 419 interval=interval/60; 420 sum=sum+interval*0.3; 421 } 422 return sum; 423 } 424 425 } 426 class Tools { 427 public void setInfo(Format f, ArrayList<User> user) { 428 int call; 429 call = this.isAccounted(f.getInfo(0), user); 430 CallRecord record = new CallRecord(); 431 if(f.getInfo(1).length()==4||f.getInfo(1).length()==3) { 432 record.setCallingNumber(f.getInfo(0)); 433 record.setCallingAddressAreaCode(f.getInfo(1)); 434 record.setAnswerNumber(f.getInfo(2)); 435 if(f.getInfo(3).length()==4||f.getInfo(3).length()==3) { 436 record.setAnswerAddressAreaCode(f.getInfo(3)); 437 record.setStartTime(f.getstartTime(4)); 438 record.setendTime(f.getendTime(4)); 439 if (!record.getAnswerAddressAreaCode().matches("079\\d||0701")) { 440 int AnswerCall = this.isAccounted(record.getAnswerNumber(), user); 441 if (AnswerCall != -1) { 442 user.get(AnswerCall).setUserRecords(record,1); 443 } 444 } 445 }else { 446 record.setAnswerAddressAreaCode(getAreaCode(f.getInfo(2))); 447 record.setStartTime(f.getstartTime(3)); 448 record.setendTime(f.getendTime(3)); 449 } 450 }else { 451 record.setCallingNumber(f.getInfo(0)); 452 record.setCallingAddressAreaCode(getAreaCode(f.getInfo(0))); 453 record.setAnswerNumber(f.getInfo(1)); 454 if(f.getInfo(2).length()==4||f.getInfo(2).length()==3) { 455 record.setAnswerAddressAreaCode(f.getInfo(2)); 456 record.setStartTime(f.getstartTime(3)); 457 record.setendTime(f.getendTime(3)); 458 if (!record.getAnswerAddressAreaCode().matches("079\\d||0701")) { 459 int AnswerCall = this.isAccounted(record.getAnswerNumber(), user); 460 if (AnswerCall != -1) { 461 user.get(AnswerCall).setUserRecords(record,1); 462 } 463 } 464 }else { 465 record.setAnswerAddressAreaCode(getAreaCode(f.getInfo(1))); 466 record.setStartTime(f.getstartTime(2)); 467 record.setendTime(f.getendTime(2)); 468 } 469 } 470 if (call != -1) 471 user.get(call).setUserRecords(record,0); 472 } 473 474 475 public void setUser(Format t, ArrayList<User> user) { 476 User u = new User(); 477 if (isAccounted(t.getUserNumber(), user) == -1) { 478 u.setNumber(t.getUserNumber()); 479 if (t.getUserMode().matches("0")) 480 u.setChargeMode(new LandlinePhoneCharging()); 481 if (t.getUserMode().matches("1")) 482 u.setChargeMode(new MobilePhoneCharging()); 483 user.add(u); 484 } 485 } 486 487 public void setUserChargeMode(Format t, ArrayList<User> user) { 488 User u = new User(); 489 u.setNumber(t.getUserNumber()); 490 user.add(u); 491 } 492 493 public int isAccounted(String num, ArrayList<User> user) { 494 for (int i = 0; i < user.size(); i++) 495 if (user.get(i).getNumber().equals(num)) 496 return i; 497 return -1; 498 } 499 500 public void FormatOut(double x) { 501 if ((x * 1e1) % 10 != 0) 502 System.out.printf("%.1f", x); 503 else 504 System.out.print(x); 505 } 506 507 public ArrayList<User> OrderUser(ArrayList<User> user) { 508 ArrayList<User> u = new ArrayList<User>(); 509 int index = 0; 510 while (user.size() != 0) { 511 { 512 index = 0; 513 for (int j = 0; j < user.size(); j++) { 514 if (user.get(j).getNumber().compareTo(user.get(index).getNumber()) < 0) 515 index = j; 516 } 517 u.add(user.get(index)); 518 user.remove(index); 519 } 520 } 521 return u; 522 } 523 524 public String getAreaCode(String s) { 525 return s.substring(0, 4); 526 } 527 528 public int getMode(String s, ArrayList<User> user) { 529 int userNumber = this.isAccounted(s, user); 530 if (userNumber != -1) { 531 if (user.get(userNumber).getChargeMode() instanceof MobilePhoneCharging) 532 return 1; 533 else 534 return 0; 535 } else 536 return -1; 537 } 538 539 } 540 class User { 541 private UserRecords userRecords = new UserRecords(); 542 private double balance = 100; 543 private ChargeMode chargeMode; 544 private String number; 545 546 public double calBalance() { 547 return balance - this.calCost() - this.chargeMode.getMonthlyRent(); 548 } 549 550 public double calCost() { 551 return this.chargeMode.calCost(userRecords); 552 553 } 554 555 public UserRecords getUserRecords() { 556 return userRecords; 557 } 558 559 public void setUserRecords(CallRecord record,int type) { 560 if (type==0) { 561 if (record.getCallingAddressAreaCode().equals("0791")) 562 this.userRecords.addCallingInCityRecords(record); 563 else if (record.getCallingAddressAreaCode().matches("079\\d||0701")) 564 this.userRecords.addCallingInProvinceRecords(record); 565 else 566 this.userRecords.addCallingInLandRecords(record); 567 } else { 568 this.userRecords.addAnswerInLandRecords(record); 569 } 570 } 571 572 public double getBalance() { 573 return balance; 574 } 575 576 public ChargeMode getChargeMode() { 577 return chargeMode; 578 } 579 580 public void setChargeMode(ChargeMode chargeMode) { 581 this.chargeMode = chargeMode; 582 } 583 584 public String getNumber() { 585 return number; 586 } 587 588 public void setNumber(String number) { 589 this.number = number; 590 } 591 } 592 class UserRecords { 593 private ArrayList<CallRecord> callingInCityRecords =new ArrayList<CallRecord>(); 594 private ArrayList<CallRecord> callingInProvinceRecords =new ArrayList<CallRecord>(); 595 private ArrayList<CallRecord> callingInLandRecords =new ArrayList<CallRecord>(); 596 private ArrayList<CallRecord> answerInCityRecords =new ArrayList<CallRecord>(); 597 private ArrayList<CallRecord> answerInProvinceRecords =new ArrayList<CallRecord>(); 598 private ArrayList<CallRecord> answerInLandRecords =new ArrayList<CallRecord>(); 599 private ArrayList<MessageRecord> sendMessageRecords =new ArrayList<MessageRecord>(); 600 private ArrayList<MessageRecord> receiveMessageRecords =new ArrayList<MessageRecord>(); 601 602 public ArrayList<CallRecord> getCallingInCityRecords() { 603 return callingInCityRecords; 604 } 605 606 public void addCallingInCityRecords(CallRecord callingInCityRecords) { 607 this.callingInCityRecords.add(callingInCityRecords); 608 } 609 610 public ArrayList<CallRecord> getAnswerInCityRecords() { 611 return answerInCityRecords; 612 } 613 614 public void addAnswerInCityRecords(CallRecord answerInCityRecords) { 615 this.answerInCityRecords.add(answerInCityRecords); 616 } 617 618 public ArrayList<CallRecord> getCallingInProvinceRecords() { 619 return callingInProvinceRecords; 620 } 621 622 public void addCallingInProvinceRecords(CallRecord callingInProvinceRecords) { 623 this.callingInProvinceRecords.add(callingInProvinceRecords); 624 } 625 626 public ArrayList<CallRecord> getCallingInLandRecords() { 627 return callingInLandRecords; 628 } 629 630 public void addCallingInLandRecords(CallRecord callingInLandRecords) { 631 this.callingInLandRecords.add(callingInLandRecords); 632 } 633 634 public ArrayList<CallRecord> getAnswerInProvinceRecords() { 635 return answerInProvinceRecords; 636 } 637 638 public void addAnswerInProvinceRecords(CallRecord answerInProvinceRecords) { 639 this.answerInProvinceRecords.add(answerInProvinceRecords); 640 } 641 642 public ArrayList<CallRecord> getAnswerInLandRecords() { 643 return answerInLandRecords; 644 } 645 646 public void addAnswerInLandRecords(CallRecord answerInLandRecords) { 647 this.answerInLandRecords.add(answerInLandRecords); 648 } 649 650 public ArrayList<MessageRecord> getSendMessageRecords() { 651 return sendMessageRecords; 652 } 653 654 public void addSendMessageRecords(MessageRecord sendMessageRecords) { 655 this.sendMessageRecords.add(sendMessageRecords); 656 } 657 658 public ArrayList<MessageRecord> getReceiveMessageRecords() { 659 return receiveMessageRecords; 660 } 661 662 public void addReceiveMessageRecords(MessageRecord receiveMessageRecords) { 663 this.receiveMessageRecords.add(receiveMessageRecords); 664 } 665 666 }View Code
在刚开始看到题目仅仅是添加了手机计费规则以为会很简单,直到真正开始实现代码时才发现需要修改的地方变多了,比如接受和处理数据的方式与上一题有了较大的差别。由于处理数据的方式变得更加复杂,在本次作业中出现了函数复杂度超出了合理范围的情况。还有改进空间。
题目三:
实现一个简单的电信计费程序,针对手机的短信采用如下计费方式:
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 import java.util.ArrayList; 2 import java.text.ParseException; 3 import java.text.SimpleDateFormat; 4 import java.util.Date; 5 import java.util.Scanner; 6 public class Main { 7 public static void main(String[] arges) { 8 Scanner input = new Scanner(System.in); 9 String data = input.nextLine(); 10 Format f = new Format(data); 11 Tools t = new Tools(); 12 ArrayList<User> user = new ArrayList<User>(); 13 while (!data.equals("end")) { 14 if (f.isFromat()) { 15 if (f.getType() == 'u') 16 t.setUser(f, user); 17 else 18 t.setInfo(f, user); 19 } 20 data = input.nextLine(); 21 f = new Format(data); 22 } 23 user = t.OrderUser(user); 24 for (int i = 0; i < user.size(); i++) { 25 System.out.print(user.get(i).getNumber()+" "); 26 System.out.print(String.format("%.1f", user.get(i).calCost())); 27 System.out.print(" "); 28 System.out.print(String.format("%.1f", user.get(i).calBalance())); 29 System.out.print("\n"); 30 } 31 input.close(); 32 } 33 34 } 35 abstract class ChargeMode { 36 protected ArrayList<MessageChargeRule> chargeRules = new ArrayList<>(); 37 38 39 public abstract double calCost(UserRecords MessageChargeRule); 40 public abstract double getMonthlyRent(); 41 } 42 abstract class ChargeRules { 43 44 } 45 abstract class CommunicationRecord { 46 protected String callingNumber; 47 protected String answerNumber; 48 public String getCallingNumber() { 49 return callingNumber; 50 } 51 public void setCallingNumber(String callingNumber) { 52 this.callingNumber = callingNumber; 53 } 54 public String getAnswerNumber() { 55 return answerNumber; 56 } 57 public void setAnswerNumber(String answerNumber) { 58 this.answerNumber = answerNumber; 59 } 60 } 61 class Format { 62 String s; 63 SimpleDateFormat Format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss"); 64 65 Format(String s) { 66 this.s = s; 67 } 68 69 public String getInfo(int n) { 70 return s.substring(2).split(" ")[n]; 71 72 } 73 74 public String getUserNumber() { 75 return s.substring(2).split(" ")[0]; 76 77 } 78 79 public String getUserMode() { 80 return s.substring(2).split(" ")[1]; 81 82 } 83 public String getCallingNumber() { 84 // TODO Auto-generated method stub 85 return s.substring(2, 13); 86 } 87 88 public String getAnswerNumber() { 89 // TODO Auto-generated method stub 90 return s.substring(14, 25); 91 } 92 93 public String getMessage() { 94 // TODO Auto-generated method stub 95 return s.substring(26); 96 } 97 98 public Date getstartTime(int n) { 99 Date startTime = null; 100 String detail[]; 101 detail = s.substring(n).split(" "); 102 String StartTime = detail[n].concat(" " + detail[n + 1]); 103 try { 104 startTime = Format.parse(StartTime); 105 } catch (ParseException e) { 106 107 e.printStackTrace(); 108 } 109 return startTime; 110 } 111 112 public Date getendTime(int n) { 113 Date endTime = null; 114 String detail[]; 115 detail = s.substring(2).split(" "); 116 String EndTime = detail[n + 2].concat(" " + detail[n + 3]); 117 try { 118 endTime = Format.parse(EndTime); 119 } catch (ParseException e) { 120 121 e.printStackTrace(); 122 } 123 return endTime; 124 125 } 126 127 public char getType() { 128 return s.charAt(0); 129 } 130 131 public boolean isFromat() { 132 if(s.equals("")) 133 return false; 134 char type = s.charAt(0); 135 if (type == 'u') { 136 return AccountFormat(); 137 } else if (type == 'm') { 138 return InfoFormat(); 139 } else 140 return false; 141 } 142 143 private boolean InfoFormat() { 144 String tPattern = "m-1\\d{10}\\s" + "1\\d{10}\\s" 145 + ".*"; 146 if(s.matches(tPattern)){ 147 String s1=getMessage(); 148 for(int i=0;i<s1.length();i++) { 149 if(!s1.substring(i, i+1).matches("[0-9]|[a-z]|[A-Z]|\\s|\\,|\\.")) 150 return false; 151 } 152 return true; 153 } 154 else 155 return false; 156 } 157 158 private boolean AccountFormat() { 159 String uPattern = "u-1\\d{10}\\s3"; 160 return s.matches(uPattern); 161 // return true; 162 } 163 164 } 165 abstract class MessageChargeRule extends ChargeRules{ 166 abstract public double calCost(UserRecords userRecords) ; 167 } 168 class MessageCharging extends ChargeMode{ 169 public MessageCharging() { 170 super(); 171 chargeRules.add(new SendMessageRule ()); 172 } 173 @Override 174 public double calCost(UserRecords userRecords) { 175 return this.chargeRules.get(0).calCost(userRecords); 176 } 177 178 @Override 179 public double getMonthlyRent() { 180 // TODO Auto-generated method stub 181 return 0; 182 } 183 184 } 185 class MessageRecord extends CommunicationRecord{ 186 private String message; 187 188 public String getMessage() { 189 return message; 190 } 191 192 public void setMessage(String message) { 193 this.message = message; 194 } 195 196 } 197 class SendMessageRule extends MessageChargeRule{ 198 199 @Override 200 public double calCost(UserRecords userRecords) { 201 double sum=0; 202 int num=0; 203 for(int i=0;i<userRecords.getSendMessageRecords().size();i++) { 204 if(userRecords.getSendMessageRecords().get(i).getMessage().length()<=10) 205 num++; 206 else { 207 if(userRecords.getSendMessageRecords().get(i).getMessage().length()%10==0) { 208 num+=userRecords.getSendMessageRecords().get(i).getMessage().length()/10; 209 } 210 else 211 { 212 num+=userRecords.getSendMessageRecords().get(i).getMessage().length()/10+1; 213 } 214 } 215 } 216 if(num>0&&num<=3) { 217 sum=num*0.1; 218 }else if(num>3&&num<=5) { 219 sum=0.3+(num-3)*0.2; 220 }else if(num>5){ 221 sum=0.7+(num-5)*0.3; 222 } 223 return sum; 224 } 225 226 227 } 228 class Tools { 229 public void setInfo(Format f, ArrayList<User> user) { 230 int call; 231 call = this.isAccounted(f.getInfo(0), user); 232 MessageRecord record = new MessageRecord(); 233 if(call!=-1) { 234 record.setCallingNumber(f.getCallingNumber()); 235 record.setAnswerNumber(f.getAnswerNumber()); 236 record.setMessage(f.getMessage()); 237 user.get(call).setUserRecords(record); 238 } 239 } 240 241 public void setUser(Format t, ArrayList<User> user) { 242 User u = new User(); 243 if (isAccounted(t.getUserNumber(), user) == -1) { 244 u.setNumber(t.getUserNumber()); 245 u.setChargeMode(new MessageCharging()); 246 user.add(u); 247 } 248 } 249 250 public void setUserChargeMode(Format t, ArrayList<User> user) { 251 User u = new User(); 252 u.setNumber(t.getUserNumber()); 253 user.add(u); 254 } 255 256 public int isAccounted(String num, ArrayList<User> user) { 257 for (int i = 0; i < user.size(); i++) 258 if (user.get(i).getNumber().equals(num)) 259 return i; 260 return -1; 261 } 262 263 public void FormatOut(double x) { 264 if ((x * 1e1) % 10 != 0) 265 System.out.printf("%.1f", x); 266 else 267 System.out.print(x); 268 } 269 270 public ArrayList<User> OrderUser(ArrayList<User> user) { 271 ArrayList<User> u = new ArrayList<User>(); 272 int index = 0; 273 while (user.size() != 0) { 274 { 275 index = 0; 276 for (int j = 0; j < user.size(); j++) { 277 if (user.get(j).getNumber().compareTo(user.get(index).getNumber()) < 0) 278 index = j; 279 } 280 u.add(user.get(index)); 281 user.remove(index); 282 } 283 } 284 return u; 285 } 286 287 288 289 290 291 }class User { 292 private UserRecords userRecords = new UserRecords(); 293 private double balance = 100; 294 private ChargeMode chargeMode; 295 private String number; 296 297 public double calBalance() { 298 return balance - this.calCost() - this.chargeMode.getMonthlyRent(); 299 } 300 301 public double calCost() { 302 return this.chargeMode.calCost(userRecords); 303 304 } 305 306 public UserRecords getUserRecords() { 307 return userRecords; 308 } 309 310 public void setUserRecords(MessageRecord record) { 311 this.userRecords.addSendMessageRecords(record); 312 } 313 314 public double getBalance() { 315 return balance; 316 } 317 318 public ChargeMode getChargeMode() { 319 return chargeMode; 320 } 321 322 public void setChargeMode(ChargeMode chargeMode) { 323 this.chargeMode = chargeMode; 324 } 325 326 public String getNumber() { 327 return number; 328 } 329 330 public void setNumber(String number) { 331 this.number = number; 332 } 333 } 334 class UserRecords { 335 private ArrayList<MessageRecord> sendMessageRecords =new ArrayList<MessageRecord>(); 336 private ArrayList<MessageRecord> receiveMessageRecords =new ArrayList<MessageRecord>(); 337 338 public ArrayList<MessageRecord> getSendMessageRecords() { 339 return sendMessageRecords; 340 } 341 342 public void addSendMessageRecords(MessageRecord sendMessageRecords) { 343 this.sendMessageRecords.add(sendMessageRecords); 344 } 345 346 public ArrayList<MessageRecord> getReceiveMessageRecords() { 347 return receiveMessageRecords; 348 } 349 350 public void addReceiveMessageRecords(MessageRecord receiveMessageRecords) { 351 this.receiveMessageRecords.add(receiveMessageRecords); 352 } 353 354 }View Code
此次题目仅仅是对于短信的计费规则,少了许多的判断格式条件,题目难度下降明显,不过在分析代码复杂度时发现还是存在函数复杂度过高的问题,应该与上次作业出现的问题一样,同时存在一个费用计算的复杂度过高的问题,还有改进空间。
三.踩坑心得
电信计费系列一:
刚看到题目提供的类图时还是听震惊的,没想到这样一道简单的计费规则题目还有这么复杂的类图关系,刚开始写代码的时候看类图一直是似懂非懂,只能照着葫芦画瓢,先把类图上所有的类建好,然后挨个分析作用,这是一个很漫长又很折磨的过程,我们需要把自己的思路完全放在这个类图之上,限制了自己的想法。最后完全读懂了类图之后实现要求很简单,问题还是出现在格式判断上,题目要求只判断时间格式,所以我很正常的去网上搜索到了可以使用parse方法将输入的时间与正确时间的格式进行比对,匹配错误就抛出异常,看似是一个很完美的方法,但是写道最后也会有几个测试点一直过不去,在询问了同学后放弃了使用抛出异常的方法,还是使用了最朴实无华的正则表达式方法,即使正则表达式没有判断座机区号,年份格式,闰年依然成功全通测试点,这也为我第二次的电信计费修改代码埋下了伏笔。
电信计费系列二:
系列二虽然添加了手机计费,但是还是存在着座机通话,我就试着把第一次的代码放上去提交,结果全是非零返回,这时的我还没有意识到问题的严重性,没办法只能开始修改代码处理数据,对于怎样判断是手机号还是座机号,最好的方法还是通过这一条数据之后的数据长度是不是4,如果是4那么这一条就是手机号,否则就是座机,我就是通过这个方法成功提交获得了不少的分数,但就是有点过不去,不用多想 ,就是格式判断的问题,我回过头来看正则表达式,但是怎么看都没问题,当时就想会不会是自己没有判断闰年导致的错误,我又花了好长一段时间把年份是闰年的判断了,加了个2月份是29天 的情况,结果还是答案不对,实在没有办法的我就开始对每一条正则表达开始测试,先是一个一个注释,这样还真让我找到问题在哪,原来是我年份的正则不对,话不多说,直接百度年份正则表达式怎么写,复制粘贴,多通过了一个测试点。同样另外一个格式问题,手机号必须是1开头,我没有做判断,起初原因还是题目上说的一句话,说什么手机格式 和座机格式错误不做判断,应该还是这一条要求的理解有误。
电信计费系列三:
系列三相较于前两个系列难度下降不少,最主要的原因还是少了时间的格式判断,所以我一开始写完代码高高兴兴的提交后本以为会直接满分,结果就是一半的分数都没有,还是因为自己没有仔细看题,题目要求了短信内容格式,我没有做任何判断就进行了计算,不过到最后我也没有找到一个很好的方法来判断短信的格式,我是先判断了短信内容是字符,然后判断具体内容比如大小写字母,数字等等,希望有会更好方法的大佬教教我。获取短信内容也是一个坑。最好不要先把输入的数据按空格分割,因为短信的内容也会有空格,最好的是从固定的位置往后切,这样一定会得到完整的短信内容。计算短信费用也是一个坑,题目上说了超过三条计费会有变化,如果没有对样例进行计算的话,很容易就把超过 3条的情况直接按一个费用计算,其实题目真正要求是超出3条的部分用一种计费方式,没超过的用另外一种。
四.改进建议
系列一二里面都是存在一些函数的复杂度较高,还可以进一步的修改提高代码的可读性。在系列一中对于一些类的理解有误,比如landlinephoneincity应该是打电话在市内的记录,但是我把他当成了接电话的,好在第一题的复杂度不高,理解错误还是可以通过测试点,在系列二就没那么好运了我只好重新写了系列一的一些代码。
五.总结
这几周主要学习内容转变了方向,老师上课开始讲起了代码规范性,以及结构的设计等,听的是云里雾里,不过在后半部分讲的Javafx还是很有用,这也是我从开始写代码第一次接触到图形化编程,虽然Javafx使用的人并不多,但是我还是很认真的学习了不少功能,并且打算在接下来的实验中将自己写的农夫过河改编为图形化界面,让他变为一个真正的游戏。
标签:return,String,ArrayList,PTA,oop,new,public,2022.12,user From: https://www.cnblogs.com/okdexiu/p/16950001.html