본문 바로가기

Algorithm/BeakJoon

[BaekJoon 2852] NBA 농구

안녕하세요. 오늘은 백준 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