안녕하세요. 오늘은 백준 2852번 NBA 농구라는 문제를 가져왔습니다.
문자열, 구현 쪽 문제입니다.
문제는 다음과 같습니다.
Team 1이 골을 넣었는데, 만약에 Team 2가 다음 골을 넣었으면 Team 1이 이기고 있던 시간에 Team 2가 방금 골 넣은 시간 - Team 1 이 마지막으로 넣은 시간을 더해주면서 문제를 해결하면 됩니다.
간단하게 제가 푼 소스코드를 먼저 살펴보겠습니다.
<소스코드>
#include <bits/stdc++.h>
using namespace std;
int n, team;
int score[3];
string winning[3]={"00:00", "00:00", "00:00"};
string last_goal, inp;
string calc(string cur, string last) {
int cur_h=stoi(cur.substr(0,cur.find(":"))), cur_m=stoi(cur.substr(cur.find(":")+1)),
last_h=stoi(last.substr(0,last.find(":"))), last_m=stoi(last.substr(last.find(":")+1));
if(last_m>cur_m) {
cur_m += 60, cur_h-=1;
}
return to_string(cur_h-last_h) + ":" + to_string(cur_m-last_m);
}
string checkForm(string s) {
int hour = stoi(s.substr(0, s.find(":"))), minute=stoi(s.substr(s.find(":")+1));
hour += minute/60, minute %= 60;
string ret_h = to_string(hour), ret_m = to_string(minute);
if(ret_h.size()==1) ret_h = "0"+ret_h;
if(ret_m.size()==1) ret_m = "0"+ret_m;
return ret_h + ":" + ret_m;
}
string res_sum(string a, string b) {
int a_h=stoi(a.substr(0,a.find(":"))), a_m=stoi(a.substr(a.find(":")+1)),
b_h=stoi(b.substr(0,b.find(":"))), b_m=stoi(b.substr(b.find(":")+1));
return to_string(a_h+b_h) + ":" + to_string(a_m+b_m);
}
int main(void) {
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
cin >> n;
for(int i = 0; i < n; i++) {
cin >> team >> inp;
if(score[1] == score[2]) {
score[team]++;
last_goal=inp;
continue;
}
score[team]++;
if(score[1] == score[2]) {
int lastWinningTeam = (team==1? 2 : 1);
winning[lastWinningTeam] = res_sum(winning[lastWinningTeam], calc(inp, last_goal));
}
}
if(score[1] != score[2]) {
int lastWinningTeam = (score[1]>=score[2]? 1 : 2);
winning[lastWinningTeam] = res_sum(winning[lastWinningTeam], calc("48:00", last_goal));
}
cout << checkForm(winning[1]) << endl;
cout << checkForm(winning[2]) << endl;
return 0;
}
score라는 배열에 team 1과 team 2의 점수를 각각 인덱스 1, 2에 저장하여 매번 더해나갑니다. 이는 현재 이기고 있는 팀이 누구인지 확인하기 위해서입니다.
1. 만약에 score가 동점이라면 -> 현재 인풋으로 받은 시간 이전까지는 동점을 유지했다는 것이므로 특정 팀이 이기기 시작한 시각입니다. 따라서 score를 증가시키고, 마지막 골의 시간을 저장해 줍니다.
2. 1번 조건을 통과하지 못했다면 두 팀의 점수가 다르다는 뜻입니다. 이 시점에서 score[team]을 증가시켜줍니다.
3. 만약에 score[team]을 증가시킨 결과가 동점이라면 이전까지 어느 특정 팀이 이기고 있고 이번 골로 인해 동점이 되었다는 뜻입니다. 따라서 현재 시각 - last_goal을 이기고 있던 팀의 점수에 더해줍니다.
4. 1~3 반복
5. 만약에 루프를 탈출했는데 두 팀의 점수가 같지 않다면 끝나는 시각 - 마지막으로 골을 넣은 시각을 이기고 있는 팀에 더해줍니다.
위의 알고리즘으로 ac를 받을 수 있었습니다.
하지만 이제 이 문제를 다른방법으로 접근할 수 있는데, prev라는 변수를 선언해서 이전에 넣은 골 타임을 매번 갱신해서 더해주는 방법입니다.
다음과 같은 코드로 해결할 수 있습니다.
<소스코드>
#include <iostream>
using namespace std;
int main() {
int n, prevTime = 0, isWinning = 0;
int teamScore[3] = {0};
int teamWinningTime[3] = {0};
cin >> n;
for(int i = 0; i < n; i++) {
int teamN, curTime;
string input;
cin >> teamN >> input;
curTime = ((input[0]-'0') * 10 + input[1] - '0') * 60 + ((input[3]-'0') * 10 + input[4] - '0');
teamScore[teamN]++;
teamWinningTime[isWinning] += curTime - prevTime;
prevTime = curTime;
isWinning = teamScore[2] > teamScore[1] ? 2 : teamScore[1] > teamScore[2] ? 1 : 0;
}
teamWinningTime[isWinning] += (48 * 60) - prevTime;
printf("%02d:%02d\n", teamWinningTime[1] / 60, teamWinningTime[1] % 60);
printf("%02d:%02d\n", teamWinningTime[2] / 60, teamWinningTime[2] % 60);
}
실제 제 동기가 썼던 코드입니다.
1. curTime이라는 변수는 현재 인풋으로 받은 시간입니다. 일단 분으로 환산한 뒤, 모든 계산을 분으로만 진행합니다.
2. TeamScore는 위 코드의 score 배열과 같은 역할입니다.
3. isWinning이라는 변수는 현재 이기고 있는 팀을 확인합니다. 저희는 바로 이전 시간을 알고 있고, 그 이전 시간까지의 과정은 모두 저장을 하면서 진행했기 때문에 이번에도 이기고 있는 팀에 현재시간 - 이전 시간을 더해주기만 하면 됩니다.
4. 1~3 반복
5. 마지막으로 끝나는 시점에 이기고 있는 팀의 시간을 더해줍니다.
6. 출력은 이제 시간단위로 모두 환산한 뒤, printf %02d 서식을 활용하여 두 자리로 맞추어 출력해줍니다.
또한 위 코드의 경우 5번 과정에서 점수를 비교하는 과정이 없는데, 필요 없는 값을 모두 TeamScore[0]에 넣어두었기 때문입니다. teamWinning[isWinning]값을 모든 테스트 케이스에 대해 마지막에 더해주지만 실제로 isWinning이 0이라면 출력하지 않기 때문에 문제없이 ac 받을 수 있습니다.
오늘도 동기의 가르침을 받으며...
*저의 글에 대한 피드백이나 지적은 언제나 환영합니다.
'Algorithm > BeakJoon' 카테고리의 다른 글
[BaekJoon 14319] 종이조각 (0) | 2021.07.23 |
---|---|
[BaekJoon 3015] 오아시스 재결합 (0) | 2021.07.19 |
[BaekJoon 15684] 사다리 조작 (0) | 2021.07.18 |
[BaekJoon 4659] 비밀번호 발음하기 (1) | 2021.07.08 |
[BackJoon4375] 1 (0) | 2021.07.03 |