2212번: 센서

첫째 줄에 센서의 개수 N(1<=N<=10,000), 둘째 줄에 집중국의 개수 K(1<=K<=1000)가 주어진다. 셋째 줄에는 N개의 센서의 좌표가 한 개의 정수로 N개 주어진다. 각 좌표 사이에는 빈 칸이 하나 이상 있으며

www.acmicpc.net

 


 

  • 생각

쉽게 생각하면 k개의 집중국으로 모든 센서를 커버할 수 있는 각 집중국 범위의 합을 구하는 문제이다.

 

그리디로 접근을 했다. 센서의 위치를 정렬하고 서로의 인접 거리를 계산한 뒤 기지국을 인접 거리가 긴 위치 순서대로 K개 배치하면 수신 가능 영역의 거리의 합의 최솟값을 구할 수 있게 된다.

 

 

- 예를 들어 N = 6, K = 2 일 경우

 

 

  • 코드

정답 코드 : 그리디 방식으로 풀어낸 코드이다.

 

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

public class Main {
	private static int N, K, answer;
	private static int[] array;

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

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

		N = Integer.parseInt(br.readLine());
		K = Integer.parseInt(br.readLine());
		answer = 0;
		array = new int[N];

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

		int[] temp = new int[N - 1];
		for (int i = 0; i < N - 1; i++) {
			temp[i] = array[i + 1] - array[i];
		}
		Arrays.sort(temp);

		for (int i = 0; i < N - K; i++)
			answer += temp[i];

	}
}

 

14226번: 이모티콘

영선이는 매우 기쁘기 때문에, 효빈이에게 스마일 이모티콘을 S개 보내려고 한다. 영선이는 이미 화면에 이모티콘 1개를 입력했다. 이제, 다음과 같은 3가지 연산만 사용해서 이모티콘을 S개 만

www.acmicpc.net


 

  • 생각

문제를 읽었을 때, dp문제였지만 bfs 방식을 사용해도 될 것같았다. (시간안에 들어올지가 문제인데 넉넉할 것 같다고 판단함)

bfs를 사용해서 모든 경우의수로 이동해보면서 해당하는 숫자에 도달했을때 depth를 구했다.

방문 처리를 2차원배열로 해서 현재개수와 클립보드에 저장된 갯수 두가지로 체크하면서 이동했다.

 

dp방식은 잘 모르겠다..ㅜ (dp 방식으로 풀어본 사람을 찾아보려했는데 java로 푼 사람중에 dp로 푼 사람이 없었다.)

 

  • 코드

정답 코드 : bfs방식으로 구현하였다. 

 

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

public class Main {
	private static int S, answer;
	private static boolean[][] check;

	public static void main(String[] args) throws Exception {
		SetData();
		bfs();
		System.out.println(answer);
	}
	
	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		S = Integer.parseInt(br.readLine());
		check = new boolean[1001][1001];	
		answer = 0;
	}
	
	private static void bfs() {
        Queue<int []> queue = new LinkedList<>();
        queue.offer(new int[] {1,1,1});
        check[1][1] = true;
        
        while(!queue.isEmpty()){
        	int location[] = queue.peek();
            
            if(location[0] == S){
                answer = location[2];
                break;
            }
            
            if(location[0] - 1 != 0 && !check[location[0] - 1][location[1]]){
                queue.offer(new int[] {location[0] - 1, location[1], location[2] + 1});
                check[location[0] - 1][location[1]] = true;
            }
            
            if(!check[location[0]][location[0]]){
                queue.offer(new int[] {location[0], location[0], location[2] + 1});
                check[location[0]][location[0]] = true;
            }
            
            if(location[0] + location[1] <= S && !check[location[0] + location[1]][location[1]]){
            	queue.offer(new int[] {location[0] + location[1], location[1], location[2] + 1});
                check[location[0] + location[1]][location[1]] = true;
            }
            
            queue.poll();
        }
	}
}

 


  • 생각

몇개의 배열을 쫙 나열하면 구현할 수 있는 수준의 점화식이였다.

배열의 결과는

1 -> 2

2 -> 2

3 -> 3
4 -> 5

5 -> 8

느낌이 오는가?? 구하고 싶은 index에서 index-1, index-2의 값을 더 해주면 된다.

 

  •  코드

  - 점화식 : i번째 index의 값은 i-1와 i-2의 index의 값 합이라는 걸 토대로 구현하였다.

 

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

public class Main {
	
	static int n;	
	static int[] dp;
	
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		n = Integer.parseInt(br.readLine());
		dp = new int[1001];
		
		dp[1] = 1;
		dp[2] = 2;
		
		for (int i = 3; i <1001 ; i ++) {	
			dp[i] = (dp[i-1] + dp[i-2]) % 10007;
		}
		
		System.out.println(dp[n]);
	}
}

 

 

나중에 다시 풀어본 코드 : 배열에 접근할 때 런타임 에러에만 유의하면 될 것 같다.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
	private static int N;
	private static int[] dp;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(dp[N]);
	}
	
	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		N = Integer.parseInt(br.readLine());
		dp = new int[N + 1];
		
		dp[1] = 1;
		if(N == 1) return;
		dp[2] = 2;
		if(N == 2) return;
		for (int i = 3; i <= N; i++) {
			dp[i] = (dp[i - 1] + dp[i - 2]) % 10007;
		}
	}
}

ㅠㅒㅓ


 

  • 생각

다이나믹프로그래밍 문제이다. 점화식의 생성 계기는 dp(N) 을 구할때 dp(N-1) + dp(N-2)에서 dp(N-2) 즉 2*(N-2)의 직사각형을 구하는 방법은 마지막에 2*2타일을 채우는 방법, 1*2 타일로 채우는 방법 2가지가 있으므로 dp(N) = dp(N-1) + dp(N-2) *2가 된다

 

  • 코드

정답 코드 : 1칸일 땐 세로로 1개, 2칸일 땐 2x2한개 2x1 두개 총 2개, N-1번의 칸에 타일 한개를 추가하는 방법과 N-2번의 칸에 2개 짜리 타일을 추가하는 방법으로 점화식을 세움.

 

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int N = Integer.parseInt(br.readLine());
		if (N == 1) {
			System.out.println(1);
			System.exit(0);
		}
		if (N == 2) {
			System.out.println(3);
			System.exit(0);
		}
		int[] dp = new int[N + 1];
		dp[1] = 1;
		dp[2] = 3;
		for (int i = 3; i <= N; i++) {
			dp[i] = (dp[i - 1] + dp[i - 2]*2) % 10007;
		}
		System.out.println(dp[N]);
	}
}

 

다시 풀어본 코드 : N이 1, 2인 경우 반복문으로 들어가게되면 런타임이 뜨는데 해당 경우를 생각을 안해서 런타임이 한번 떴다. 또, N이 1인경우 dp[2]를 들어갈 경우 런타임이 뜬다. 

 

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
	private static int N;
	private static int[] dp;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(dp[N]);
	}
	
	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		N = Integer.parseInt(br.readLine());
		dp = new int[N + 1];
		
		dp[1] = 1;
		if(N == 1) return;
		dp[2] = 3;
		if(N == 2) return;
		for (int i = 3; i <= N; i++) {
			dp[i] = (dp[i - 1] + dp[i - 2]*2) % 10007;
		}
	}
}

 


 

  • 생각

알고리즘을 처음 시작할 때쯤 풀었던 문제였다. 재채점되면서 틀리게 된 문제이다.

 

질문검색에서 찾아보니 기존 코드는 아래와 같은 방법에서 오답의 결과를 냈다.

642 // 정답: 10, 오답: 11

643 // 정답: 11, 오답: 12

생각해보니 문제는 3과 2 모두가 떨어질 때 발생했다. 기존 코드는 if, if로 한것이 아닌 if, else if로 해서 6의 배수일 경우 2, 3으로 떨어지는 경우를 모두 체크를 해야했는데 그러지 못했었다.

 

  • 처음 코드
import java.util.Scanner;

public class Main {
    public static void main(String args[]) {
    	Scanner scanner = new Scanner(System.in);
        
    	int X = scanner.nextInt(); //정수 값 받아옴
    	int[] array = new int[X+1];		//배열 선언
    	
    	for(int i = 2; i<=X;i++) {
			array[i] = array[i - 1] + 1;
			if (i % 3 == 0)
				array[i] = Math.min(array[i], array[i / 3] + 1);
			else if (i % 2 == 0)
				array[i] = Math.min(array[i], array[i / 2] + 1);
    	}
    	System.out.println(array[X]);
		
	}
}

 

 

  • 나중 코드
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
	static int X;
	static int[] array;

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

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

		X = Integer.parseInt(br.readLine());
		array = new int[X + 1];
		
		for (int i = 2; i <= X; i++) {
			array[i] = array[i - 1] + 1;
			if (i % 2 == 0)
				array[i] = Math.min(array[i], array[i / 2] + 1);
			if (i % 3 == 0)
				array[i] = Math.min(array[i], array[i / 3] + 1);
		}
	}
}

 

 

 

- 정리

  - java 입력 받는 법

import java.util.Scanner;   //import

    	Scanner scanner = new Scanner(System.in);
	int X = scanner.nextInt(); //정수 값 받아옴

  - 최소값 가져오는 법

 Math.min(변수 1, 변수 2);

[]

 


 

  • 생각

기존에 비슷한 문제를 푼 적이 있었다. 풀었던 코드에서 문제조건에 따라서 살짝 수정해주었다.

 

[JAVA] 백준 17141번 : 연구소 2

코드 정답 코드 : dfs를 통해 depth가 M일 때 bfs를 통해서 최소시간을 구해주었다. import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.LinkedLi..

qazyj.tistory.com

 

문제를 읽어보면 한가지 다른점은 비활성 상태인 바이러스 위치까지 전파할 필요가 없다는 것이다.

 

연구소2에서는 copy 함수에서 선택되지 않은 바이러스는 0으로 표시했다면, 연구소3에서는 -1로 표시했다.

 

이유는 바이러스가 전파될 때 비활성 상태인 바이러스를 통과해서 지나갈 수 있기 때문이다.

 

  • 코드

정답 코드 : dfs를 통해 depth가 M일 때 bfs를 통해서 최소시간을 구해주었다.

 

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

public class Main {
	private static int N, M, count, min;
	private static int[][] array;
	private static boolean[] check;
	private static ArrayList<int[]> virus;
	private static int[] x = { 0, 0, -1, 1 };
	private static int[] y = { -1, 1, 0, 0 };

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(min);
	}
	
	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());
		array = new int[N][N];
		virus = new ArrayList<>();
		count = 0;
		min = Integer.MAX_VALUE;

		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < N; j++) {
				array[i][j] = Integer.parseInt(st.nextToken());
				if (array[i][j] == 2)
					virus.add(new int[] { i, j });
				if (array[i][j] == 0)
					count++;
			}
		}
		
		check = new boolean[virus.size()];
		
		if (count != 0)
			dfs(0, 0);
		else
			min = 0;
		
		if(min == Integer.MAX_VALUE)
			min = -1;
	}

	private static void dfs(int start, int depth) {
		// Basecase
		if (depth == M) {
			int[][] tempArray = copyArray();
			bfs(tempArray, count);
			return;
		}
		for (int i = start; i < virus.size(); i++) {
			check[i] = true;
			dfs(i+1, depth + 1);
			check[i] = false;
		}
	}

	private static void bfs(int[][] tempArray, int count) {
		Queue<int[]> queue = new LinkedList<>();
		for (int i = 0; i < virus.size(); i++) {
			if (check[i])
				queue.add(virus.get(i));
		}
		
		int time = 0;
		while (!queue.isEmpty()) {
			if (time >= min) break;
			
			int length = queue.size();
			for (int j = 0; j < length; j++) {
				int[] location = queue.poll();
				
				for (int direction = 0; direction < 4; direction++) {
					int r = location[0] + x[direction];
					int c = location[1] + y[direction];
					
					if (r < 0 || c < 0 || r >= N || c >= N) continue;
					if (tempArray[r][c] == 1 || tempArray[r][c] == 2) continue;
					if (tempArray[r][c] == 0) 	count--;
					
					tempArray[r][c] = 2;
					queue.add(new int[] { r, c });
				}
			}
			
			time++;
			if (count == 0) {
				min = time;
				return;
			}
		}
	}

	private static int[][] copyArray() {
		int[][] result = new int[N][N];
		for (int i = 0; i < N; i++) {
			System.arraycopy(array[i], 0, result[i], 0, N);
		}
		for (int i = 0; i < virus.size(); i++) {
			if (!check[i]) {
				int[] location = virus.get(i);
				result[location[0]][location[1]] = -1;
			}
		}
		return result;
	}
}

 

 


 

  • 생각

3달만에 다시 풀어보았다. 로그인이 안되어있어서 익숙한데 안푼 문제인줄알고 풀었다.

접근방식은 전과 같은 방법으로 접근하였고 결과는 메모리, 시간 모두 더 높게 나왔지만 코드는 비슷했다.

(java8 버전과 java11버전일때의 다른 점인것 같다) 

 

푼 방식은 대문자 알파벳은 26개가 최대라는 점을 이용하여 풀었다.

배열을 26크기로 만든 뒤

N개의 모든 A위치의 값은 0 index에 넣고

N개의 모든 B위치의 값은 1 index에 넣고

.... Z까지 한 뒤 배열을 거꾸로 정렬해준 뒤, 가장 값이 큰 알파벳부터 9, 8, 7 ... 1까지 입력해주면 된다.

 

  • 코드

정답 코드 : 백트래킹 문제였는데 수학적으로 접근하는게 더 좋은 것 같다. 입력은 대문자 알파벳(26개)로 제한되어 있다. int 배열 index에 0~25를 A~Z입력일 때 math.pow(10,자릿수)만큼 더 해준다음 가장 높은 값부터 9~0곱해주며 더 해준다.

 

import java.io.*;
import java.util.*;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int []number = new int[26];
		
		int N = Integer.parseInt(br.readLine());
		for(int i = 0; i < N; i++) {
			String temp = br.readLine();
			int tmp = 0;
			for(int j = temp.length()-1; j >= 0 ;j--) {
				number[temp.charAt(j) - 'A'] += Math.pow(10,tmp++);
			}			
		}
		Arrays.sort(number);
		
		int result = 0, num=9;
		for(int i = 25; i >= 0; i--) {
			if(number[i]==0) break;
			result+=number[i]*num--;
		}
		System.out.println(result);		
    }
}

 

3달 뒤 혼자 다시 풀어본 코드 : 방식은 위와 비슷한 방식으로 풀었다.

 

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

public class Main {
	static int answer;

	public static void main(String[] args) throws Exception {
		SetData();
		System.out.println(answer);
	}
	
	private static void SetData() throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int N = Integer.parseInt(br.readLine());
		answer = 0;
		int[] array = new int[26];
		
		for(int i = 0; i < N; i++) {
			String s = br.readLine();
			int temp = 1;
			for(int j = s.length() - 1; j >= 0; j--) {
				array[s.charAt(j) - 'A'] += temp;
				temp *= 10;
			}
		}
		
		Arrays.sort(array);
		int temp = 25;
		for(int i = 9; i >= 1; i--) {
			answer += array[temp--]*i;
		}
	}
	
}

 

 

2448번: 별 찍기 - 11

첫째 줄에 N이 주어진다. N은 항상 3×2k 수이다. (3, 6, 12, 24, 48, ...) (0 ≤ k ≤ 10, k는 정수)

www.acmicpc.net


 

  • 생각

이 문제처럼 반복되는 모양의 구조를 "프랙탈 구조"라고 한다.

반복되는 구조를 잘 파악하는 것이 핵심이다.

 

똑같은 모양을 가지고 구조를 만들기 때문에 첫 모양은 규칙을 찾으려 하지 말고 임의로 생성해준다.

    *   
   * * 
  *****

 

반복되는 모양을 만들어준 뒤 작은 수부터 규칙을 찾아나가며 풀면 될 것 같다.

  • 코드

정답 코드 : 반복되는 구조를 파악한 뒤 작은 수부터 규칙을 찾아나가며 풀면 되는 문제이다.

 

import java.awt.List;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
	static int N;
	static StringBuilder sb;

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

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

		sb = new StringBuilder();
		N = Integer.parseInt(br.readLine());
		ArrayList<String> printingStart = new ArrayList<>();
		// N이 3일때 세팅
		printingStart.add("  *  ");
		printingStart.add(" * * ");
		printingStart.add("*****");

		// N => 3*2^k, 3, 6, 12, 24, 48, ... 이니깐 k가 1번째, 2번째 를 나타냄
		for (int k = 1; 3 * (int) Math.pow(2, k) <= N; k++) { // 6입력부터 루프 실행
			setStar(printingStart);
		}

		for (String s : printingStart) {
			sb.append(s + "\n");
		}
	}

	private static void setStar(ArrayList<String> printingStart) {
		StringBuilder s = new StringBuilder();
		StringBuilder s2 = new StringBuilder();

		int size = printingStart.size();

		for (int i = 0; i < size; i++) {
			s.delete(0, s.length());

			// 전 단계의 그림을 아래 하나, 옆 하나 이렇게 총 2개 복사
			s.append(printingStart.get(i)); // 전 단계의 그림
			s.append(" "); // 공백
			s.append(printingStart.get(i)); // 전 단계의 그림

			printingStart.add(s.toString());

			// 전 단계 그림의 왼쪽, 오른쪽에 공백 추가
			s2.delete(0, s.length());
			for (int j = 0; size > j; j++) {
				s2.append(" ");
			}

			printingStart.set(i, s2.toString() + printingStart.get(i) + s2.toString());
		}
	}
}

 

 

+ Recent posts