• 생각

1. 그냥 반복문 O(N^2)만큼 돌리면 시간 초과?? ==>> 시간 초과

 

2. 이분 탐색으로 하면?? 

 

3. Arraylist를 이용해서 max 값과 listsize를 빼가며 값을 정확히 도출하는 방법 ==>> 시간 초과

 

  • 코드

정답 코드 : 이분 탐색으로하면 시간초과 나지 않고 잘 동작한다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int N;
	static long count;
	static long[] number, temp;

	public static void main(String[] args) throws Exception {
		SetData();
		Sort(0, N-1);
		System.out.println(count);
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;

		N = Integer.parseInt(br.readLine());
		number = new long[N];
		temp = new long[N];
		count = 0;

		st = new StringTokenizer(br.readLine());
		for (int i = 0; i < N; i++)
			number[i] = Long.parseLong(st.nextToken());
	}

	public static void Sort(int start, int end) {
		if(start < end) {
			int middle = (start+end)/2;
			Sort(start, middle);
			Sort(middle+1, end);
			merge(start,middle,end);
		}
	}

	private static void merge(int start, int middle, int end) {
		int startToMidStartIndex = start;
		int midToEndStartIndex = middle+1;
		int startTempIndex = start;
	
		while(startToMidStartIndex<=middle && midToEndStartIndex<=end) {
			if(number[startToMidStartIndex] <= number[midToEndStartIndex]) {
				temp[startTempIndex++] = number[startToMidStartIndex++];
			}else {
				temp[startTempIndex++] = number[midToEndStartIndex++];
				count +=  (middle + 1 - startToMidStartIndex);
			}
		}
		while(startToMidStartIndex<=middle)
			temp[startTempIndex++] = number[startToMidStartIndex++];
		while(midToEndStartIndex<=end)
			temp[startTempIndex++] = number[midToEndStartIndex++];
		
		for(int k=start; k<=end; k++) {
			number[k] = temp[k];
		}
		
	}
}

 

 


 

  • 생각

1. 문제를 일고 처음에 이해가 되지 않았는데, 예제를 보고선 도킹을 할 때 현재 번호보다 낮은 번호에만 도킹을 할 수 있다는 사실을 알게되었다.

 

  • 코드

정답 코드 : gate[index] == index 일때만 도킹을 해준다. 도킹을 했을댄 index의 값을 -1해줘서 해당 인덱스에는 다신 도킹할 수 없게 하였다. gate[index] != index 경우에는 해당 게이트보다 낮은 게이트를 재귀로 모두 다 돌아본 다음 도킹 가능한 게이트가 있으면 도킹, index가 0까지 가는 경우 도킹을 종료한다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int G, P;
	static int[] gate, airplane;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(FindMaxValue());
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		G = Integer.parseInt(br.readLine());
		P = Integer.parseInt(br.readLine());
		gate = new int[G + 1];
		airplane = new int[P + 1];

		for (int i = 1; i <= G; i++)
			gate[i] = i;

		for (int i = 1; i <= P; i++)
			airplane[i] = Integer.parseInt(br.readLine());
	}

	private static int FindMaxValue() {
		int count = 0;

		for (int i = 1; i <= P; i++) {
			if (docking(airplane[i]) < 0)
				break;
			count++;
		}

		return count;
	}

	private static int docking(int index) {
		// basecase (게이트 번호의 값이 0이면 도킹 불가)
		if (gate[index] == 0)	return -1;
		
		if (gate[index] == index)	// 도킹을 아직 시도하지 않은 게이트라면
			gate[index]--;
		else						// 도킹을 한 게이트라면 현재 게이트보다 낮은 게이트를  찾기 위해 재귀를 돔.
			gate[index] = docking(gate[index]);
		
		return gate[index];
	}
}

 


 

  • 생각

1. DFS - 멀티탭의 모든 칸이 꽉 찰때마다 모든 멀티탭의 플러그를 한번씩 빼가며 DFS를 돌림. 정확하지만 시간초과 가능성 높음

 

2. 멀티탭에 꽂으면서 꽉찼을 때만 뽑을 콘센트를 찾는 작업을 진행함. 콘센트를 빼는 것은 뒤에 가장 적게오는 콘센트를 뽑는다.

 

 

  • 코드

정답 코드 : 2번 방법으로 콘센트가 꽉 찼을 때만 뒤에 남아있는 콘센트 번호 중에 가장 적게 나오는 번호를 뽑는다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int N, K;
	static int[] array;
	static HashSet<Integer> powerSocket;	// 멀티탭에 먼저 꽂았는지 꽂지 않았는지는 상관이 없다. HashSet 사용

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(FindMinValue());
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		K = Integer.parseInt(st.nextToken());
		powerSocket = new HashSet<Integer>();
		array = new int[K];

		st = new StringTokenizer(br.readLine());
		for (int i = 0; i < K; i++)
			array[i] = Integer.parseInt(st.nextToken());

	}

	private static int FindMinValue() {
		int count = 0;
		
		for(int i = 0; i < K; i++) {
			// 콘센트가 꽉차지 않거나 콘센트에 꽂혀있는 번호이면 continue
			if(powerSocket.contains(array[i])  || isPossible(array[i])) 
				continue;
			
			// 콘센트가 꽉차고 콘센트에 꽂혀있는 번호가 아닐 시
			int max = -1, pick = -1;
			for (int num : powerSocket) {
				int temp = 0;	// temp를 통해 뒤에 가장 적게 오는 수를 지워줌
				for (int j = i + 1; j < K; j++) {
					if (num == array[j]) {
						break;
					}
					temp++;
				}
				if (temp > max) {
					pick = num;
					max = temp;
				}

			}
			powerSocket.remove(pick);
			powerSocket.add(array[i]);

			count++;
		}
		
		return count;
	}
	
	private static boolean isPossible(int item) {
		if (powerSocket.size() < N) {
			powerSocket.add(item);
			return true;
		}
		return false;
	}
	
}

 

'algorithm' 카테고리의 다른 글

[JAVA] 백준 1517번 : 버블 소트  (0) 2020.11.12
[JAVA] 백준 10775번 : 공항  (0) 2020.11.10
[JAVA] 백준 1202번 : 보석 도둑  (0) 2020.11.09
[JAVA] 백준 15683번 : 감시  (0) 2020.11.06
[JAVA] 백준 2011번 : 암호코드  (0) 2020.11.05

 


 

  • 생각

1. 가방에 넣을 수 있는 보석을 차례대로 dfs로 넣는다? => 모든 경우의 수를 다 탐색한다. 정확하지만 시간초과의 가능성 존재

 

2. 가방의 무게가 수용할 수 있는 최소 무게 가방부터 넣을 수 있는 보석을 확인 후 넣을 수 있는 최대의 가격 보석을 넣는다. 

tip) 2차원 배열 정렬

 

  • 코드

정답 코드 : 1번 방법은 시간초과가 나올 것 같아서 2번 방법을 시행했다. 2번 방법을 쉽게 푸는 팁이 있다면 array.sort로 배열을 오름차순으로 정렬 후 pritorityqueue 우선순위 큐(큐에 있는 값들이 2개 이상이면 오름차순으로 큐에 들어감)를 사용하여 쉽게 해결할 수 있었다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int N, K;
	static int[][] jewelry;
	static int[] bag;
	static long maxValue;

	public static void main(String[] args) throws Exception {
		SetData();
		FindMaxValue();
		System.out.println(maxValue);
	}

	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		K = Integer.parseInt(st.nextToken());
		maxValue = 0;
		jewelry = new int[N][2];
		bag = new int[K];

		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			jewelry[i][0] = Integer.parseInt(st.nextToken());
			jewelry[i][1] = Integer.parseInt(st.nextToken());
		}

		for (int i = 0; i < K; i++)
			bag[i] = Integer.parseInt(br.readLine());

		// 2차원 배열 sort
		Arrays.sort(jewelry, new Comparator<int[]>() {
			@Override
			public int compare(int[] o1, int[] o2) {
				// TODO Auto-generated method stub
				return o1[0] - o2[0];
			};

		});
		Arrays.sort(bag);
	}

	private static void FindMaxValue() {
		// 우선 순위 큐로 해야지 오름차순 정렬이 되서 작은 값이 맨 먼저 나오게됌
		Queue<Integer> queue = new PriorityQueue<>();
		int j = 0;
		for (int i = 0; i < K; i++) {
			while (j < N && jewelry[j][0] <= bag[i]) { // 앞에서 담은것은 제외해야 하므로 while문과 j를 사용
				queue.add(-jewelry[j][1]);	// -를 해주는 이유는 -를 해야지 양수 최대값이 음수로 넣었을 때 오름차순에서 맨 앞으로 가져올 수 있게한다. 
				j++;
			}
			if (!queue.isEmpty()) { // for문 한번에 한번만 더한다.
				maxValue += Math.abs(queue.poll());	// 음수로 바꿔줬던 수에 절대값을 씌워서 양수로 다시 나오게함
			}
		}

	}
}

 

'algorithm' 카테고리의 다른 글

[JAVA] 백준 10775번 : 공항  (0) 2020.11.10
[JAVA] 백준 1700번 : 멀티탭 스케줄링  (0) 2020.11.09
[JAVA] 백준 15683번 : 감시  (0) 2020.11.06
[JAVA] 백준 2011번 : 암호코드  (0) 2020.11.05
[JAVA] 백준 1062번 : 가르침  (0) 2020.11.04

 


 

  • 생각

1. DFS로 돌리는 경우 - 1번 4개, 2번 2개, 3번 4개, 4번 4개, 5번 1개로 모든 방향으로 확인하면서 복구 시킨다. 

 ==>> 시간초과 뜰 것 같았는데 역시 시간초과가 뜬다. 어떻게 고쳐야하지?

 

  • 코드

정답 코드 : 똑같이 dfs로 풀고 비슷한 방식으로 풀었는데 이건 왜 빠른지 찾아보자.. 아직 이해안함

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int R, C, result, cnt, tmpResult;
	static int[][] grid;
	static int[][][] camPos;
	static int[] camCount, camAcc;
	static int[][] camDir;
	static int[] dirTypes = {4, 2, 4, 4, 1};
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine().trim());
		
		R = Integer.parseInt(st.nextToken());
		C = Integer.parseInt(st.nextToken());
		
		grid = new int[R][C];
		
		result = Integer.MAX_VALUE;
		
		camPos = new int[5][8][2];
		camDir = new int[5][8];
		
		for (int i = 0; i < 5; i++) {
			for (int j = 0; j < 8; j++) {
				camDir[i][j] = -1;
			}
		}
		
		camCount = new int[5];
		
		for (int r = 0; r < R; r++) {
			st = new StringTokenizer(br.readLine().trim());
			for (int c = 0; c < C; c++) {
				grid[r][c] = Integer.parseInt(st.nextToken());
				
				if(grid[r][c] == 0)
					continue;
				else if(grid[r][c] == 6)
					continue;
				else {
					camPos[grid[r][c]-1][camCount[grid[r][c]-1]][0] = r;
					camPos[grid[r][c]-1][camCount[grid[r][c]-1]][1] = c;
//					System.out.println(r+","+c);
					camCount[grid[r][c]-1] ++;
				}
			}
		}
		
		camAcc = new int[5];
		
		for (int i = 0; i < 5; i++) {
			camAcc[i] = camCount[i];
		}
		
		for (int i = 1; i < 5; i++) {
			camAcc[i] = camAcc[i-1] + camAcc[i];
		}
		
		DFS(0);
		
		System.out.println(result);
	}
	private static void DFS(int count) {
		if(count == camAcc[4]) {
			
//			for (int i = 0; i < 5; i++) {
//				for (int j = 0; j < 8; j++) {
//					System.out.print(camDir[i][j]+" ");
//				}
//				System.out.println();
//			}
//			System.out.println();
			
			int[][] tmpGrid = new int[R][C];
			for (int r = 0; r < R; r++) {
				for (int c = 0; c < C; c++) {
					tmpGrid[r][c] = grid[r][c];
				}
			}
			
			tmpResult = 0;
			
			for (int i = 0; i < 5; i++) {
				for (int j = 0; j < camCount[i]; j++) {
					if(i == 0) {
						dirCheck(camDir[i][j], tmpGrid, camPos[i][j][0], camPos[i][j][1]);
					} else if(i == 1) {
						dirCheck(camDir[i][j], tmpGrid, camPos[i][j][0], camPos[i][j][1]);
						dirCheck(camDir[i][j]+2, tmpGrid, camPos[i][j][0], camPos[i][j][1]);
					} else if(i == 2) {
						dirCheck(camDir[i][j], tmpGrid, camPos[i][j][0], camPos[i][j][1]);
						dirCheck((camDir[i][j]+1)%4, tmpGrid, camPos[i][j][0], camPos[i][j][1]);
					} else if(i == 3) {
						dirCheck(camDir[i][j], tmpGrid, camPos[i][j][0], camPos[i][j][1]);
						dirCheck((camDir[i][j]+1)%4, tmpGrid, camPos[i][j][0], camPos[i][j][1]);
						dirCheck((camDir[i][j]+2)%4, tmpGrid, camPos[i][j][0], camPos[i][j][1]);
					} else {
						dirCheck(camDir[i][j], tmpGrid, camPos[i][j][0], camPos[i][j][1]);
						dirCheck((camDir[i][j]+1)%4, tmpGrid, camPos[i][j][0], camPos[i][j][1]);
						dirCheck((camDir[i][j]+2)%4, tmpGrid, camPos[i][j][0], camPos[i][j][1]);
						dirCheck((camDir[i][j]+3)%4, tmpGrid, camPos[i][j][0], camPos[i][j][1]);
					}
				}
			}
			
			for (int r = 0; r < R; r++) {
				for (int c = 0; c < C; c++) {
					if(tmpGrid[r][c] == 0)
						tmpResult++;
				}
			}
			
			if(result > tmpResult) {
				result = tmpResult;
//				for (int r = 0; r < R; r++) {
//					for (int c = 0; c < C; c++) {
//						System.out.print(tmpGrid[r][c]+" ");
//					}
//					System.out.println();
//				}
//				
//				System.out.println();
//				
			}
			
			return;
		}
		int type = -1;
		int idx = -1;
		
//		System.out.println(count);
		
		for (int i = 0; i < 5; i++) {
			if(count < camAcc[i]) {
				type = i;
				if(i == 0)
					idx = count;
				else
					idx = count - camAcc[i-1];
				break;
			}
		}
		
		for (int i = 0; i < dirTypes[type]; i++) {
			camDir[type][idx] = i;
			DFS(count + 1);
		}
		
	}
	private static void dirCheck(int dir, int[][] tmpGrid, int currR, int currC) {
		int[] dr = {-1, 0, 1, 0};
		int[] dc = {0, 1, 0, -1};
		
		int tr = currR;
		int tc = currC;
		
		while(true) {
			tr += dr[dir];
			tc += dc[dir];
			
			if(tr >= R || tc >= C || tr < 0 || tc < 0)
				break;
			
			int currVal = tmpGrid[tr][tc];
			
			if(currVal == 6)
				break;
			
			if(currVal == 0) {
				tmpGrid[tr][tc] = 9;
			}
			else 
				continue;
		}
	}
}

 

 

 

실패 코드 : 앞선 1의 시간초과뜬 코드이다. 시간을 줄일 방법이 생각이 안난다..

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
	static int N, M, count, minValue;
	static int[][] array;
	static int[] x, y;

	public static void main(String[] args) throws Exception {
		SetData();
		DFS(0);
		System.out.println(minValue);
	}

	// 데이터
	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());

		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		count = 0; // 벽이 아닌 방향이 있는 1~5 숫자가 몇개있는지 count (basecase로 두기 위함)
		array = new int[N][M];
		x = new int[8];
		y = new int[8];
		minValue = Integer.MAX_VALUE; // 사각지대 최소 개수

		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < M; j++) {
				array[i][j] = Integer.parseInt(st.nextToken());

				// 미리 cctv 좌표를 저장한다.
				if (array[i][j] != 0 && array[i][j] != 6) {
					x[count] = i;
					y[count] = j;
					count++;
				}
			}
		}
	}

	private static void DFS(int startIndex) {

		// basecase 모든 cctv를 확인해본 결과
		if (startIndex == count) {
			minValue = Math.min(minValue, RemainCCTV());
			return;
		}

		for (int i = startIndex; i < count; i++) {
			if (array[x[i]][y[i]] == 1) {
				CheckCCTV(x[i], y[i], startIndex, 1);
			} else if (array[x[i]][y[i]] == 2) {
				CheckCCTV(x[i], y[i], startIndex, 2);
			} else if (array[x[i]][y[i]] == 3) {
				CheckCCTV(x[i], y[i], startIndex, 3);
			} else if (array[x[i]][y[i]] == 4) {
				CheckCCTV(x[i], y[i], startIndex, 4);
			} else if (array[x[i]][y[i]] == 5) {
				CheckCCTV(x[i], y[i], startIndex, 5);
			}
		}
	}

	private static void CheckCCTV(int i, int j, int startIndex, int numberOfCCTV) {
		switch (numberOfCCTV) {
		case 1:
			GoUp(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoDown(i,j);
			DFS(startIndex + 1);
			GoBackDown(i,j);
			GoLeft(i,j);
			DFS(startIndex + 1);
			GoBackLeft(i,j);
			GoRight(i,j);
			DFS(startIndex + 1);
			GoBackRight(i,j);
			break;
		case 2:
			GoUp(i,j);
			GoDown(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoBackDown(i,j);
			GoLeft(i,j);
			GoRight(i,j);
			DFS(startIndex + 1);
			GoBackLeft(i,j);
			GoBackRight(i,j);
			break;
		case 3:
			GoDown(i,j);
			GoLeft(i,j);
			DFS(startIndex + 1);
			GoBackDown(i,j);
			GoBackLeft(i,j);
			GoUp(i,j);
			GoRight(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoBackRight(i,j);
			GoLeft(i,j);
			GoUp(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoBackLeft(i,j);
			GoRight(i,j);
			GoDown(i,j);
			DFS(startIndex + 1);
			GoBackRight(i,j);
			GoBackDown(i,j);
			break;
		case 4:
			GoUp(i,j);
			GoDown(i,j);
			GoLeft(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoBackDown(i,j);
			GoBackLeft(i,j);
			GoUp(i,j);
			GoDown(i,j);
			GoRight(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoBackDown(i,j);
			GoBackRight(i,j);
			GoLeft(i,j);
			GoRight(i,j);
			GoUp(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoBackLeft(i,j);
			GoBackRight(i,j);
			GoLeft(i,j);
			GoRight(i,j);
			GoDown(i,j);
			DFS(startIndex + 1);
			GoBackLeft(i,j);
			GoBackRight(i,j);
			GoBackDown(i,j);
			break;
		case 5:
			GoUp(i,j);
			GoDown(i,j);
			GoLeft(i,j);
			GoRight(i,j);
			DFS(startIndex + 1);
			GoBackUp(i,j);
			GoBackDown(i,j);
			GoBackLeft(i,j);
			GoBackRight(i,j);
			break;
		default:
			break;
		}
	}

	private static void GoUp(int startI, int startJ) {
		for (int i = startI; i >= 0; i--) {
			if (array[i][startJ] == 6)
				break;
			if (array[i][startJ] == 0)
				array[i][startJ] = 7;
		}
	}

	private static void GoDown(int startI, int startJ) {
		for (int i = startI; i > N; i++) {
			if (array[i][startJ] == 6)
				break;
			if (array[i][startJ] == 0)
				array[i][startJ] = 7;
		}
	}

	private static void GoLeft(int startI, int startJ) {
		for (int j = startJ; j >= 0; j--) {
			if (array[startI][j] == 6)
				break;
			if (array[startI][j] == 0)
				array[startI][j] = 7;
		}
	}

	private static void GoRight(int startI, int startJ) {
		for (int j = startJ; j < M; j++) {
			if (array[startI][j] == 6)
				break;
			if (array[startI][j] == 0)
				array[startI][j] = 7;
		}
	}

	private static void GoBackUp(int startI, int startJ) {
		for (int i = startI; i >= 0; i--) {
			if (array[i][startJ] == 6)
				break;
			if (array[i][startJ] == 7)
				array[i][startJ] = 0;
		}
	}

	private static void GoBackDown(int startI, int startJ) {
		for (int i = startI; i > N; i++) {
			if (array[i][startJ] == 6)
				break;
			if (array[i][startJ] == 7)
				array[i][startJ] = 0;
		}
	}

	private static void GoBackLeft(int startI, int startJ) {
		for (int j = startJ; j >= 0; j--) {
			if (array[startI][j] == 6)
				break;
			if (array[startI][j] == 7)
				array[startI][j] = 0;
		}
	}

	private static void GoBackRight(int startI, int startJ) {
		for (int j = startJ; j < M; j++) {
			if (array[startI][j] == 6)
				break;
			if (array[startI][j] == 7)
				array[startI][j] = 0;
		}
	}

	private static int RemainCCTV() {
		int countOfCCTV = 0;

		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (array[i][j] == 0)
					countOfCCTV++;
			}
		}

		return countOfCCTV;
	}

}

 


 

  • 생각

1. 해당 index와 전 index의 값이 10 이상 26이하면 +1을 또 해준다. (* 0은 무시해야 된다.)

 

  • 코드

정답 코드 : 기존 1개의 문자는 나온다는 가정하에 2글자가 있으면 +1을 더 해주면서 dp배열 돌린다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	static String N;
	static long[] dp;

	public static void main(String[] args) throws Exception {
		SetData();
		SaveMaxValue();
		System.out.println(dp[N.length()] % 1000000);
	}

	// 데이터
	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		N = br.readLine();
		
		// 0으로 시작하는 경우 암호를 해석 할 수 없기 때문에 0을 출력하고 종료해야 된다.
		// 이 부분을 생각 안하고 있다가 애먹었다.
		if (N.charAt(0) == '0') {
			System.out.println(0);
			System.exit(0);
		}

		dp = new long[N.length() + 1];
		dp[0] = 1;
		dp[1] = 1;
	}

	private static void SaveMaxValue() {
		for (int i = 1; i < N.length(); i++) {
			int previousNumber = N.charAt(i - 1) - '0';
			int currentNumber = N.charAt(i) - '0';
			// 1 글자만
			if (currentNumber >= 1 && currentNumber <= 9) {
				dp[i + 1] += dp[i];
			}
			// 2 글자도 가능
			if (!(previousNumber == 0 || previousNumber > 2 || (previousNumber == 2 && currentNumber > 6))) {
				dp[i + 1] += dp[i - 1];
			}

			dp[i + 1] %= 1000000;
		}
	}

}

 


 

  • 생각

1. 문자 앞 4, 뒤 4를 제외한 문자열만 문자열 배열에 가져와서, a~z개 모든 조합의 6개를 dfs를 통해 돌리면서 확인한다. ==>> 해봤는데 시간초과 뜸.

===>>> 시간초과 뜬 이유는 기존 알파벳 5개를 제외한 나머지 알파벳으로 dfs를 돌려야 했다. (문제 잘못 이해...)

 

 

  • 코드

정답 코드 : dfs를 통해 K - 5 개의 모든 알파벳 조합을 돌렸다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int maxValue, N, K;
	static String[] s;
	static boolean[] check;

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());

		N = Integer.parseInt(st.nextToken());
		K = Integer.parseInt(st.nextToken());
		maxValue = 0;
		s = new String[N];
		check = new boolean[26];

		// 무조건 배워야하는 단어 5개
		check['a' - 'a'] = true;
		check['n' - 'a'] = true;
		check['t' - 'a'] = true;
		check['i' - 'a'] = true;
		check['c' - 'a'] = true;

		// 앞 anta 뒤 tica를 제외한 문자열을 갖고온다.
		for (int i = 0; i < N; i++) {
			String temp = br.readLine();
			s[i] = temp.substring(4, temp.length() - 4);
		}

		dfs(0, 0);
		System.out.println(maxValue);
	}

	private static void dfs(int count, int start) {
		// basecase
		if (count == K - 5) {
			int temp = 0;
			for (int i = 0; i < N; i++) {
				boolean flag = true;

				// 배운 알파벳이 있는지 check
				for (int j = 0; j < s[i].length(); j++) {
					if (!check[s[i].charAt(j) - 'a']) {
						flag = false;
						break;
					}
				}

				if (flag) 
					temp++;				
			}
			maxValue = Math.max(temp, maxValue);
			return;
		}

		for (int i = start; i < 26; i++) {
			if (!check[i]) {
				check[i] = true;
				dfs(count + 1, i);
				check[i] = false;
			}
		}
	}
}

 

 

 


 

  • 생각

1. 배열을 만들어서 지어도 되는 건물 index를 먼저 채워 넣으며 다른 건물을 더 해준다. 이걸 어떻게 구현해야 될 지 찾아보니 이런 상황에서 풀 때 쓰면 좋은 알고리즘을 찾았다. 위상 정렬이라는 알고리즘이다.

 

 

위상 정렬 (velog.io/@max9106/Algorithm-%EC%9C%84%EC%83%81-%EC%A0%95%EB%A0%ACTopology-Sort - 직접 정리해서 링크 바꿔 놓자!) 

- 어떤 일을 하는 순서를 찾는 알고리즘이다. 즉, 방향 그래프에 존재하는 각 정점들의 선행 순서를 위배하지 않으면서 모든 정점을 나열하는 것

- DAG(Directed Acyclic Graph: 사이클이 존재하지 않는 방향 그래프)에만 적용할 수 있다.

 

 

 

  • 코드

정답 코드 : 위상 정렬을 큐를 사용하여 구현한 코드이다. 위상 정렬을 처음 접해 보았는데 코드가 깔끔하다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = null;
		
        int N = Integer.parseInt(br.readLine());
        ArrayList<ArrayList<Integer>> preBuildingNumber = new ArrayList<>();
 
        for (int i = 0; i <= N; i++) {
            preBuildingNumber.add(new ArrayList<>());
        }
 
        int[] indegree = new int[N + 1]; // 특정 건물을 짓기 전에 먼저 지어야 할 건물의 개수
        int[] times = new int[N + 1]; // 특정 건물을 짓는 데 걸리는 시간
 
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
 
            times[i] = Integer.parseInt(st.nextToken());	// 해당 건물을 짓기 위한 시간
            while (true) {
                int preBuildingNumberTemp = Integer.parseInt(st.nextToken());
 
                if (preBuildingNumberTemp == -1)
                    break;
 
                preBuildingNumber.get(preBuildingNumberTemp).add(i);
 
                indegree[i]++;		// 해당 건물을 짓기 전 지어야 할 건물의 수를 더해준다.
            }
        }
 
        String timeForBuilding = topologicalSort(preBuildingNumber, indegree, times, N);
 
        System.out.print(timeForBuilding);

    }
    
    // 위상 정렬
    public static String topologicalSort(ArrayList<ArrayList<Integer>> a, int[] indegree, int[] times, int N) {
        Queue<Integer> queue = new LinkedList<>();
        StringBuilder sb = new StringBuilder();
        
        // 먼저 지어야할 건물이 없는 건물을 큐에 집어 넣음. 해당 큐에 있는 건물을 먼저 짓는다.
        for (int i = 1; i <= N; i++) {
            if (indegree[i] == 0) {
                queue.offer(i);
            }
        }
        
        // 특정 건물을 짓기 전까지 걸린 시간 누적
        int[] result = new int[N + 1];
 
        while (!queue.isEmpty()) {
            int now = queue.poll();
 
            for (int next : a.get(now)) {
                indegree[next]--;
                
                // indegree를 줄여나가는 과정
                // result[next] = max(result[next], result[now] + times[now])
                // 위의 수식을 활용하여 result의 값을 초기화하는 것이 핵심
                result[next] = Math.max(result[next], result[now] + times[now]);
 
                if (indegree[next] == 0) {
                    queue.offer(next);
                }
            }
        }
        
        // 특정 건물을 짓기 전 먼저 지어야할 건물의 시간 + 특정 건물을 짓는 시간
        for (int i = 1; i <= N; i++) {
            sb.append((result[i] + times[i]) + "\n");
        }
 
        return sb.toString();
    }
}

+ Recent posts