PAT甲级1016 Phone Bills :[C++题解]字符串处理(复杂题)(C语言格式化读入、输出很便利!!!)
文章目錄
- 題目分析
- 題目鏈接
題目分析
原題:
長途電話公司按以下規則向客戶收費:
撥打長途電話每分鐘要花費一定的費用,具體收費取決于撥打電話的時間。
客戶開始撥打長途電話的時間將被記錄,客戶掛斷電話的時間也將被記錄。
每個月都要給客戶發送一次話費賬單,賬單中應包含每次通話記錄以及相關收費等信息。
給定一組電話記錄,你的工作是為客戶準備帳單。
輸入格式
輸入包含兩部分:費率結構和電話記錄。
費率結構由一行組成,該行包含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
題目分析:
特點:題干很長,需要花時間去閱讀。
分析:這道題有點不會處理,在糾結用不用結構體。
另外需要提到的一點是:讀入數據是沒有順序的,可能off-line的在前,也可能on-line的在前。但是好在 同一個人打電話區域是不重疊的!!!什么意思呢?意思是 張三1月1號7:00開始打電話,打到1月1號7:15,這是一次完整的通話,數據中不會出現張三1月1號7:10又開始打電話(上一次數據是7:00 ~ 7:15,7:10開始打電話與之沖突)這種數據。
想到了這一點,就可以僅僅按照時間來排序,而不用在排序的時候還要考慮online還是offline。 因為 按時間排好之后一次完整的通話一定是在一起的,即上面的是online,下一個就是同一次通話的offline。沒有在一起的就是非法數據。
學習很多C語言的優點
sprintf函數的作用:將一個格式化的字符串輸入到另一個字符串中。sprintf()一般是三個參數:第一個是目的字符串,第二個是格式,比如“%02d”,第三個就是變量。
比如
char buf[30]; int day ,hour ,minute; //假設已經賦過值 sprintf(buf , "%02d:%02d:%02d", day , hour , minute); //意思是格式化為xx:xx:xx 這樣的形式 xx不足兩位的補零sprintf()函數的用法總結
還有 .c_str()函數,
使用printf("%s")輸出的時候需要 char * ,不能使用string類型, 需要函數 c_str()進行轉換:把string轉換為 char *
warning: format '%s' expects argument of type 'char*', but argument 2 has type 'std::string' {aka 'std::basic_string<char>'} [-Wformat=]ac代碼
學習別人的代碼
#include<bits/stdc++.h> using namespace std;const int N =1010,M=31*1440+10; // 每天1440分鐘,每月最多31天。另外再多開10個大小 int cost[24];struct Record{int minutes; //字符串時間轉化為分鐘數string state;string format_time;//按照時間從小到大排序, 重載 < 運算符bool operator< (const Record& t)const{return minutes < t.minutes;} };//hash表映射 // 第一個是name ,后面是一個vector ,vector里面存了一個結構體。 //同名字的記錄都push_back到 vector中作為一項。/* 差不多是這樣的 張三對應一個vector: {一條記錄(結構體),一條記錄,一條記錄,...} 李四對應一個vector:{一條記錄(結構體),一條記錄,一條記錄,...} */ map<string,vector<Record>> persons;double sum[M];// 前綴和數組,用來求本月1號0點0分 到任何一天任何時間花費的錢數int n;int main(){for(int i=0;i<24;i++) cin >>cost[i];// 預處理 本月1號00:00分 到 本月 任意時間x號xx:xx分 打電話的花費//i 這里遍歷的是一個月中的所有分鐘 // %1440 是看在幾號(一天1440分鐘) ;而/60是看在哪個小時時間段,用來看此時的電話費for(int i=0; i< M ;i++) sum[i] =sum[i-1] + cost[ (i- 1) % 1440 / 60 ] /100.0;cin>>n;char name[25] ,state[10], format_time[20];int month ,day ,hour ,minute;for(int i=0;i<n;i++){scanf("%s %d:%d:%d:%d %s",name, &month, &day, &hour, &minute, state);sprintf(format_time ,"%02d:%02d:%02d", day ,hour ,minute);int minutes = (day -1) * 1440 +hour * 60 + minute; //記錄距離該月1號00時00分的分鐘數,方便前綴和求解persons[name].push_back({minutes, state, format_time}); //結構體壓入姓名對應的vector} for( const auto & p :persons ){auto name = p.first;auto records = p.second; //是map里面的那個vectorsort(records.begin(),records.end());double total = 0;for(long unsigned i=0 ; i + 1 < records.size() ;i ++){ //每次遍歷兩條記錄auto a = records[i] ,b = records[i+1];if(a.state == "on-line" && b.state =="off-line"){if(!total){printf("%s %02d\n",name.c_str(),month); // 輸出姓名和月份}cout<< a.format_time <<" "<<b.format_time<<" ";double charge = sum[b.minutes] -sum[a.minutes];printf("%d $%.2lf\n",b.minutes - a.minutes, charge);total+=charge;}}if(total) printf("Total amount: $%.2lf\n",total);}}ac代碼:
自己獨立寫的代碼:vector自定義排序還是喜歡重寫cmp函數,這里比較的是結構體。
題目鏈接
PAT甲級1016 Phone Bills
總結
以上是生活随笔為你收集整理的PAT甲级1016 Phone Bills :[C++题解]字符串处理(复杂题)(C语言格式化读入、输出很便利!!!)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PAT甲级1061 Dating:[C+
- 下一篇: PAT甲级1017 Queueing a