코딩테스트

시각(년, 월, 일,...) 문제 완전 공략 (c++)

코앤미 2023. 7. 25. 14:24

https://www.acmicpc.net/problem/18312

 

18312번: 시각

정수 N과 K가 입력되었을 때 00시 00분 00초부터 N시 59분 59초까지의 모든 시각 중에서 K가 하나라도 포함되는 모든 시각을 세는 프로그램을 작성하시오. 시각을 셀 때는 디지털 시계를 기준으로,

www.acmicpc.net

 

문제 해답

#include<iostream>
using namespace std;

#define hour 24
#define min 60
#define sec 60

int main() {
	int n, k;
	cin >> n >> k;
	long long total = 0;
	int answer = 0;
	long long end_time = (n + 1) * 60 * 60;
	for (int t = 0; t < end_time; t++) {
		int h, m, s;
		long long tmp = 1;
		s = t/(tmp) % sec;
		m = t/(tmp*= sec) % min;
		h = t/(tmp*=min) % hour;
		printf("%d:%d:%d\n", h, m, s);
		if (m%10 == k || m / 10 == k) {
			answer++;
		}
		else if (s % 10 == k || s / 10 == k) {
			answer++;
		}
		else if (h % 10 == k || h / 10 == k) {
			answer++;
		}
	}
	cout << answer << endl;
	
}

모든 시간을 최소 단위 기준으로 만든다.

(1분 -> 60초, 1시간 -> 60*60 초.....)

 

만약 1시 59분 59초를 표현하면 어떻게 될까?

시: 60*60

분: 59* 60

초: 59*1

 

즉, 만약 '초'가 60초가 넘어가면, '분'으로 넘어가고, '분'이 60분이 넘어가면 '시' 로 계산이 된다.

이를 역으로 계산할 때에도 아래와 같이, 시, 분, 초를 추출할 수 있다.

time= (60*60+58*60+59*1) ->   time/(60*60*1)%24, time/(60*1)%60, time/(1)%60 

즉, 어떤 시간을 time에서 다시 추출하기 위해선  현재시간/(해당 시간을 '초'로 환산시 단위)%(해당 시간의 최대 단위) 로 구할 수 있는 것이다.

 

 

 

 

아래와 같이 for문을 돌아서 해결하는 것도 가능하지만, 만약 시간과 시간 사이의 연산( A시각, B 시각은 어느정도 시각 차이?) 와 같은 문제를 만나면 위와 같이 long으로 묶어서 해결하는 것이 편할 것이다. 

#include <iostream>

using namespace std;

int main(void) {

	int N, K, num = 0;

	cin >> N >> K;

	for (int hour = 0; hour <= N; hour++) {
		for (int minute = 0; minute < 60; minute++) {
			for (int sec = 0; sec < 60; sec++) {
				if (hour % 10 == K || hour / 10 == K ||
					minute % 10 == K || minute / 10 == K ||
					sec % 10 == K || sec / 10 == K)
					num++;
			}
		}
	}

	cout << num;
}

 

또한, c++에는 time 관련 헤더가 있다. 서칭해서 찾은 관련 글을 아래에 정리했으니, 참고하는 것도 좋다.

하지만, 코딩 테스트 문제에서는 ,헤더 사용을 막기위해, 시간의 단위를 다르게 할 수 도 있다.( 매 달은 30일까지만 있는 것으로 계산, 1년에 3개의 달, 100개의 일 이 있는 새로운 달력 개념 등등)  그렇기에, long을 사용한 풀이를 알아두면 좋을 것이다. 

https://coding-factory.tistory.com/669

 

[C언어/C++] 두개의 날짜/시간 간격 차이 계산하기 (difftime)

프로그래밍을 하다 보면 두개의 날짜나 시간의 간격을 계산해야할 경우가 생깁니다. C언어나 C++에서는 두개의 날짜나 시간의 간격은 difftime 함수를 사용하여 구할 수 있습니다. time 헤더 파일 포

coding-factory.tistory.com

 

 

2) 시간이 친절하게 각각 int 값으로 주어지는 경우도 있지만, string에 "2022:02:11:..." 이런식으로 주어진 경우도 있다.

이럴 경우, c++에선 string의 split 함수를 직접 구현해서 ':' 기준으로 잘라서 저장해야한다.

 

아래는, 내가 string -> vector<int> ( 초, 분, 시, 일, 월, 년)  <-> longlong(전부 '초'로 전환) 의 변환함수를 구현한 예시이다.

#include<iostream>
#include<sstream>
#include<vector>
#include <algorithm>
using namespace std;
//자기 이전의 단위로 해당 단위를 구성하기 위해 필요한 양을 정의 
#define year 12  //12달 = 1년
#define mon 30
#define day 24
#define hour 60 //60분 = 1시간
#define min 60 //60초=1분
#define sec 1

long long year_sec = sec * min * day * hour * mon*year;

vector<int> time_unit = { sec,min,hour,day,mon,year };

vector<int> string_to_time(string str) {
	stringstream ss(str);
	vector<int> v;
	while (getline(ss, str, ':')) {
		v.push_back(stoi(str));
	}
	reverse(v.begin(), v.end());
	return v;
}

long long time_to_long(vector<int> time) {
	int h, m, s;
	long long tmp = 1;
	long long sum = 0;
	for (int i = 0; i < time.size(); i++) {
		tmp *= time_unit[i];
		sum += time[i] * (tmp);
	}
	return sum;
}

vector<int> long_to_time(long long t) {
	long long to_sec = year_sec;
	vector<int> time;
	for (int i = time_unit.size()-1; i >=0; i--) {
		long long now = t / to_sec;
		time.push_back(now);
		t %= to_sec;
		to_sec /= time_unit[i];
	}
	return time;
}


int main() {
	int n, k;
	long long total = 0;
	vector<int> answer;
	string st_time = "2022:11:29:23:59:59";
	vector<string> times = { "01:01:01:01","02:23:01:01" };

	vector<int> vec_stt = string_to_time(st_time);
	cout << "================ string_to_time" << endl;
	for (auto a : vec_stt) {
		cout << a << " ";
	}
	cout << endl;

	long long long_stt = time_to_long(vec_stt);
	cout << "================ time_to_long" << endl;
	cout << long_stt;
	cout << endl;

	vector<int> vv_stt = long_to_time(long_stt);

	cout << "================ long_to_time" << endl;
	for (auto a : vv_stt) {
		cout << a << " ";
	}
	cout << endl;


	
	string day1 = "2022:11:29:23:59:59", addTime = "0:0:0:0:0:1";




	cout << day1 << " + " << addTime << " =?" << endl;
	long long timeAdded = time_to_long(string_to_time(day1)) + time_to_long(string_to_time(addTime));
	vector<int> ans = long_to_time(timeAdded);
	for (auto a : ans) {//초, 분, 시, 일, 월, 년 순 출력
		cout << a << " ";
	}
	
}

 

3) 날짜 계산: Long으로 변환 x

더한 뒤, 작은 단위부터 계산하면서 최소 범위 초과시 증가시켜나가면 된다. 

#include<iostream>
#include<sstream>
#include<vector>
#include <algorithm>
using namespace std;



vector<int> add_date(vector<int> a, vector<int> b) {
	vector<int> ans;
	int add = 0;
	int sec = a[0] + b[0];
	if (sec >= 60) {
		sec -= 60;
		add = 1;
	}
	ans.push_back(sec);
	int min = a[1] + b[1]+add;
	add = 0;
	if (min >= 60) {
		min -= 60;
		add = 1;
	}
	ans.push_back(min);
	int hour = a[2] + b[2] + add;
	add = 0;
	if (hour >= 24) {
		hour -= 24;//
		add = 1;
	}
	ans.push_back(hour);
	int day = a[3] + b[3] + add;
	add = 0;
	if (day >= 31) {
		day -= 30;// 1일부터 시작. 따라서 빼고나서 1일부터... 31-30 ==1
		add = 1;
	}
	ans.push_back(day);
	int mon = a[4] + b[4] + add;
	add = 0;
	if (mon >= 13) {
		mon -= 12; //13-12 ==1 월 부터
		add = 1;
	}
	ans.push_back(mon);
	int year = a[5] + b[5] + add;
	ans.push_back(year);
	add = 0;
	return ans;

}











int main() {
	int n, k;
	long long total = 0;
	vector<int> answer;


	string day1 = "2022:12:30:23:59:59", addTime = "0:0:0:0:0:1";

	


	
	vector<int> ans = add_date(string_to_time(day1), string_to_time(addTime));
	for (auto a : ans) {//초, 분, 시, 일, 월, 년 순 출력
		cout << a << " ";
	}

}