곽로그
[백준 6064, Java] 카잉달력 본문
문제
첫번째 풀이(시간초과)
가장 간단한 풀이다. year, yearX, yearY를 하나씩 증가시키면서 yearX, yearY가 각각 x 와 y랑 같은지 체크해준다. 이때 yearX, yearY를 증가시킬 때 M, N을 넘으면 1로 초기화 시켜준다. (근데 다시 풀이를 보니까 종료조건도 틀려있다)
그런데 이 풀이의 시간복잡도는 O(MN)이다. 카잉달력의 마지막 날은 <M,N>인데 이를 1씩 카운트 하면 MN의 최소 공배수까지 가게된다. M,N의 최대 값이 40,000 인데 M*N = 1,600,000,000 은 1억을 넘어가므로 시간초과가 난다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
public static int T;
public static int destX;
public static int destY;
public static int x;
public static int y;
public static int N;
public static int M;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
T = Integer.parseInt(br.readLine().trim());
for(int t = 0; t<T ; t++){
st = new StringTokenizer(br.readLine()," ");
M = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
destX = Integer.parseInt(st.nextToken());
destY = Integer.parseInt(st.nextToken());
int result = calculateYear();
bw.write(String.valueOf(result)+"\n");
}
bw.flush();
br.close();
bw.close();
}
public static int calculateYear(){
int x = 0;
int y = 0;
int count = 0;
boolean valid = true;
while (true) {
x = x<M ? ++x : 1;
y= y< N ? ++y : 1;
++count;
if(x==destX && y == destY){
valid = true;
break;
}
if(x==M && y == N){
valid = false;
break;
}
}
return valid ? count : -1;
}
}
두번째 풀이(틀림)
서로 자리올림 단위가 다를 때는 모듈러 연산을 생각할 수 있다. 10진수를 해당 진수로 나눈 나머지 (예를 들어 10을 M으로 나눈 나머지, 10을 N으로 나눈 나머지)로 주기를 이루기 때문이다.
M = 10 이고 N = 12인 경우 x는 10이 주기고, y는 12가 주기다. 만약 <3: 9>를 구한다고 하면 3은 <3:9>까지 10진수로 count한 수를 10(M)으로 나눈 나머지가 3이고, 9는 count를 N으로 나눈 나머지가 9이다. 이 성질을 이용해서 x를 구한다음 이때의 count를 N으로 나눈 나머지가 y인지를 확인하면 된다.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
public static int T;
public static int M;
public static int N;
public static int x;
public static int y;
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
T = Integer.parseInt(br.readLine());
for(int t= 0 ;t<T; t++) {
st = new StringTokenizer(br.readLine(), " ");
M = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
x = Integer.parseInt(st.nextToken());
y = Integer.parseInt(st.nextToken());
int deadYear = getDeadYear();
int result = getYear(deadYear);
bw.write(String.valueOf(result)+"\n");
}
bw.flush();
}
public static int getDeadYear(){
//M과 N의 최소 공배수
int m = M;
int n = N;
while(n>0){
int r = m % n;
m = n;
n = r;
}
//최소공배수 = M * N / 최대공약수(m)
return M * N / m;
}
public static int getYear(int deadYear){
boolean isValid = true;
int year = x;
while(true){
if(year>deadYear){
isValid = false;
break;
}
if(year % N ==y){
isValid = true;
break;
}
year +=M;
}
return isValid ? year : -1;
}
}
세번째 풀이
두번째 풀이에서 생각하지 못했던 것은 year % N == y부분인데, 만약 N == y 이면 year % N ==0 인경우를 체크하지 못한다
따라서 이 부분에 대한 처리를 따로 해줘야한다. (반례 10 12 10 12)
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
public static int T;
public static int M;
public static int N;
public static int x;
public static int y;
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
T = Integer.parseInt(br.readLine());
for(int t= 0 ;t<T; t++) {
st = new StringTokenizer(br.readLine(), " ");
M = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
x = Integer.parseInt(st.nextToken());
y = Integer.parseInt(st.nextToken());
int deadYear = getDeadYear();
int result = getYear(deadYear);
bw.write(String.valueOf(result)+"\n");
}
bw.flush();
}
public static int getDeadYear(){
//M과 N의 최소 공배수
int m = M;
int n = N;
while(n>0){
int r = m % n;
m = n;
n = r;
}
//최소공배수 = M * N / 최대공약수(m)
return M * N / m;
}
public static int getYear(int deadYear){
boolean isValid = true;
int year = x;
while(true){
if(year>deadYear){
isValid = false;
break;
}
int tempYear = year % N ==0? N : year %N;
if(tempYear == y){
isValid = true;
break;
}
year +=M;
}
return isValid ? year : -1;
}
}
함수 안쓰는 코드
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int t, m, n, x, y;
t = Integer.parseInt(br.readLine());
for(int testCase = 0; testCase<t; testCase++){
st = new StringTokenizer(br.readLine());
m = Integer.parseInt(st.nextToken());
n = Integer.parseInt(st.nextToken());
x = Integer.parseInt(st.nextToken());
y = Integer.parseInt(st.nextToken());
int xx = x;
int year = xx;
int yy = year%n==0? n : year%n;
while(true){
//현재 x,y가 목표 x, y인가
if(xx == x && yy == y){
break;
}
//현재 x, y가 카잉달력의 마지막 해인가(-> year의 마지막)
else if(year>m*n){
year = -1;
break;
}
//현재 x,y가 목표해도 아니고 마지막 해도 아니면 다음 해를 구한다
else{
year +=m;
xx = year%m==0? m : year%m;
yy = year%n ==0? n: year%n;
}
}
bw.write(String.valueOf(year)+"\n");
}
bw.flush();
}
}
시간복잡도는 O(N) - xx를 고정시킨 후 yy를 검사하는데, yy에서 나올 수 있는 경우의 수는 N개
'알고리즘 > 백준' 카테고리의 다른 글
[백준 1912, Java] 연속합 (0) | 2020.12.07 |
---|---|
[백준 1748, Java] 수 이어 쓰기1 (0) | 2020.12.01 |
[백준 2579, Java] 계단 오르기 (0) | 2020.11.27 |
[백준 1905, Java] 01타일 (0) | 2020.11.27 |
[백준 3085, Java] 사탕 게임 (0) | 2020.11.27 |