--- tags: uva --- # Uva11052 - Economic phone calls ## 題目大意 你的手機上有通話紀錄,格式為 `MM:DD:hh:mm phone-number +/-` 其中 + 為重要的訊息,- 為不重要的訊息 並且訊息的年份能夠從訊息的時間推得(嚴格遞增為一年) 我們要在可以推的所有重要訊息年份的前提下,選擇刪掉最多的不重要訊息 並且在最後輸出留下來的訊息數 (最下面一條是最近的訊息) ## 重點觀念 ## 分析 - 先把訊息的年份找出來 - 初始化每則訊息的的最小訊息數 - 在最近的這一年 - 只要在重要的訊息後出現的就只需要自己一則訊息就可以辨識年份 - 在重要訊息後則先定為 n - i - 在其他年 - 先大致定為 n - i - 順便找 last 與最舊的重要訊息 - last 是在最近一年最新的重要訊息或是換年後的最新的訊息 - 用 dp 找出到目前的所選擇的訊息前面需要多少訊息才能辨識年份 - 在找最小訊息數時只要時間比前面的少且年份只差一年,則中間的訊息可以忽略 - 如果同一年也可以忽略 - 最後找最舊得重要訊息辨識年份所需要的訊息則數即是答案 ## 程式題目碼 ```cpp= #include <iostream> using namespace std; int main() { int n; while (cin >> n && n != 0) { int timestamp[n]; bool isImportant[n]; int year[n]; for (int i = 0; i < n; i++) { int month, day, hour, minute; char mark; scanf("%d:%d:%d:%d %*s %c", &month, &day, &hour, &minute, &mark); timestamp[i] = ((((month * 31) + day) * 24) + hour) * 60 + minute; isImportant[i] = mark == '+'; } year[0] = 0; int current_year; for (int i = 1; i < n; i++) { if (timestamp[i] <= timestamp[i - 1]) { year[i] = year[i - 1] + 1; } else { year[i] = year[i - 1]; } current_year = year[i]; } int dp[n], last = -1, first_important = -1; for (int i = n - 1; i >= 0; i--) { if (last == -1 && year[i] == current_year) { dp[i] = 1; } else { dp[i] = n - i; } if (last == -1 && (isImportant[i] || year[i] != current_year)) { last = i; } if (isImportant[i]) { first_important = i; } } for (int i = last; i >= first_important; i--) { for (int j = i + 1; j < n; j++) { if (year[i] == year[j] || (timestamp[i] >= timestamp[j] && year[j] - year[i] == 1)) { dp[i] = min(dp[i], dp[j] + 1); } else { break; } if (isImportant[j]) { break; } } } cout << dp[first_important] << endl; } return 0; } ```