Pat 甲级 1016 电话账单 (中文翻译 java 版)

这个就java版在Pat上只有一半分数,在Acwing上能过60%,这个写的头疼,还是太菜,希望大佬帮我优化一下

题目大意:

长途电话公司按以下规则向客户收费:

拨打长途电话每分钟要花费一定的费用,具体收费取决于拨打电话的时间。

客户开始拨打长途电话的时间将被记录,客户挂断电话的时间也将被记录。

每个月都要给客户发送一次话费账单,账单中应包含每次通话记录以及相关收费等信息。

给定一组电话记录,你的工作是为客户准备帐单。
输入格式

输入包含两部分:费率结构和电话记录。

费率结构由一行组成,该行包含24个非负整数,分别表示从 00:00-01:00 的收费(分/分钟),从 01:00-02:00 的收费,以此类推…

下一行包含一个正整数 N。

接下来 N行,每行包含一条记录。

每个记录由客户名称(最多 20个字符的字符串,不带空格),时间和日期(mm:dd:hh:mm)以及单词 on-line 或 off-line 组成。

所有日期都在同一个月内,每个 on-line 记录都与按时间顺序排列的同一位客户的下一条记录配对,但前提是这条记录是 off-line。

所有未与 off-line 记录配对的 on-line 记录以及未与 on-line 记录配对的 off-line 记录都必须忽略。

输入中至少包含一个成功的配对。

同一客户在同一时间不会有两个或以上的电话记录。

使用 24小时制记录时间。

输出格式

你需要为每个客户打印电话费。

账单必须按照客户姓名的字母顺序(按ASCII码顺序,大写字母在前,小写字母在后)打印。

对于每个客户,首先以示例显示的格式在一行中打印客户名称和帐单月份。

然后,对于每个通话时间段,在一行中分别打印开始和结束时间和日期(dd:hh:mm),持续时间(以分钟为单位)和通话费用。

通话必须按时间顺序列出。

最后,以示例显示的格式打印该月的总费用。

注意,没有任何有效通话记录的客户直接忽略,不予打印账单。
数据范围

1≤N≤1000

输入样例:

10 10 10 10 10 10 20 20 20 15 15 15 15 15 15 15 20 30 20 15 15 10 10 10
10
CYLL 01:01:06:01 on-line
CYLL 01:28:16:05 off-line
CYJJ 01:01:07:00 off-line
CYLL 01:01:08:03 off-line
CYJJ 01:01:05:59 on-line
aaa 01:01:01:03 on-line
aaa 01:02:00:01 on-line
CYLL 01:28:15:41 on-line
aaa 01:05:02:24 on-line
aaa 01:04:23:59 off-line

输出样例:

CYJJ 01
01:05:59 01:07:00 61 $12.10
Total amount: $12.10
CYLL 01
01:06:01 01:08:03 122 $24.40
28:15:41 28:16:05 24 $3.85
Total amount: $28.25
aaa 01
02:00:01 04:23:59 4318 $638.80
Total amount: $638.80

思路

1.先用前缀和算出所有从11 00:00开始直到月末所产生的费用,
每一秒占用数组一个内存,这样最后找到两个匹配的直接
sum[end]-sum[begin]就算出来全部的了;

cost[i]表示24的第i小时的每分钟通话费用
int M=31*1440+10   //+10防止越界不够
for(int i=0;i<24;i++){
            cost[i]=Double.parseDouble(costtemp[i]);
        }
        for(int i=1;i<M;i++) {
        	//cost[i-1]是因为01:59:00-:02:00:00这一分钟的费用是按
        	//第一个小时的费用算的
            sum[i] = sum[i - 1] + cost[(i - 1) % 1440 / 60] / 100;
        }

2.为了方便查找配对,要把所有的状态先按客户姓名的字母顺序,
再按时间先后顺序排序,这就要定义一个类,类里面有名字、时间、
状态
class Person implements Comparable<Person>{
    String name;
    String mouth;
    String  day;
    String hour;
    String minute;
    int summ;
    String state;
    double total;
    public Person(String name,String mouth,String day,String hour,String minute,String state,int summ){
        this.name=name;
        this.day=day;
        this.hour=hour;
        this.minute=minute;
        this.state=state;
        this.summ=summ;
        this.mouth=mouth;
    }
    public int compareTo(Person o){
        if(name.equals(o.name)) {
            return Integer.compare(summ, o.summ);
        }
        else {
            return name.compareTo(o.name);
        }
    }
3.这里配对要注意如果当状态是 on ,排序后下面的还是on,这条记录
就无法配对,只有当前记录和 下面一个记录 符合条件才能配对,
下下个即使符合条件也不能配对

4.当一个人结束的时候,要输出他的总费用,类似于这样
"Total amount: $12.10"
如何判断当前人的是否已近算完了,用一个last记录前一个
人的名字,如果当前名字跟前一个的名字不一样就可以输出
前一个人的账单了,这里我用hashmap把名字和费用结合起来,
但是这样会忽略最后一个人的账单

5.每个人的名字只输入一次,用栈来储存已近出现过的名字
没有出现过的就输出;

6.循环结束后还要判断一下最后一个人的总账单,还要判断
是否为空,不为空就输出

package PAT甲级;

import javax.print.DocFlavor;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
import java.util.regex.PatternSyntaxException;

public class 电话账单1016 {
    static int M=31*1440+10;//一个月多少分钟,+10怕越界
    static double []sum=new double[M];//从1月1 00:00开始直到月末所产生的费用,用前缀和
    static double []cost=new double[24];
    public static void main(String[] args) throws IOException {
        // BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
        Map<String ,Person>map=new HashMap<>();
        String tempcost=reader.readLine();
        String []costtemp=tempcost.split("\\s+");

        for(int i=0;i<24;i++){
            cost[i]=Double.parseDouble(costtemp[i]);
        }
        for(int i=1;i<M;i++) {
            sum[i] = sum[i - 1] + cost[(i - 1) % 1440 / 60] / 100;

        }
        Stack<String> stack=new Stack<>();
        int N=Integer.parseInt(reader.readLine());
        Person []person=new Person[N];
        HashMap<String,Double>mp=new HashMap<>();
        for(int i=0;i<N;i++){
		
        String temp=reader.readLine();
        //读入后按空格拆分
        String []temparr=temp.split("\\s+");
        String []time=temparr[1].split(":");
		//把所有的时间换算成秒就好判断大小
        int mouth= Integer.parseInt(time[0]);
        int day=Integer.parseInt(time[1]);
        int hour=Integer.parseInt(time[2]);
        int minute= Integer.parseInt(time[3]);
        int summinute=day*24*60+hour*60+minute;

        person[i]=new Person( temparr[0],time[0],time[1],time[2],time[3],temparr[2],summinute);

        }
        //排序
        Arrays.sort(person);
        String last="";
        for(int j=0;j<N-1;j++) {
            int flag=0;
            //只要找当前记录的下一个
            int i=j+1;
            {
                //栈有人了,且上个人的账单不为空
                if(!last.equals(person[j].name)&&!stack.isEmpty()&&mp.get(last)!=null)  {
                    System.out.println("Total amount: $"+String.format("%.2f",mp.get(last)));
                    last=person[j].name;
                }
                if (person[j].name.equals(person[i].name) && person[j].state.equals("on-line") && person[i].state.equals("off-line")) {
                    if(!stack.contains(person[j].name)) {
                        System.out.println(person[j].name+" "+person[j].mouth);
                        stack.push(person[j].name);
                        mp.put(person[j].name,0.0);
                        last=person[j].name;

                    }


                    System.out.print(person[j].day + ":" + person[j].hour + ":" + person[j].minute + " ");
                    System.out.print(person[i].day + ":" + person[i].hour + ":" + person[i].minute + " ");
                    double result=sum[person[i].summ] - sum[person[j].summ];
                    double result2=Double.parseDouble(String.format("%.2f",result));
                    System.out.println(person[i].summ - person[j].summ + " " + "$"+ String.format("%.2f",result));
                    //更新当前人的账单
                    mp.put(person[j].name,result2+mp.get(person[j].name));
                }

                // System.out.println(person[i].name + " " + person[i].summ + " " + person[i].day + " " + person[i].hour + " " + person[i].minute + " " + person[i].state);
            }
        }
        if(mp.get(last)!=null)
            System.out.println("Total amount: $"+String.format("%.2f",mp.get(last)));


    }

}
class Person implements Comparable<Person>{
    String name;
    String mouth;
    String  day;
    String hour;
    String minute;
    int summ;
    String state;
    double total;
    public Person(String name,String mouth,String day,String hour,String minute,String state,int summ){
        this.name=name;
        this.day=day;
        this.hour=hour;
        this.minute=minute;
        this.state=state;
        this.summ=summ;
        this.mouth=mouth;
    }
    public int compareTo(Person o){
        if(name.equals(o.name)) {
            return Integer.compare(summ, o.summ);
        }
        else {
            return name.compareTo(o.name);
        }
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值