Seren dev's blog
article thumbnail

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

 

14890번: 경사로

첫째 줄에 N (2 ≤ N ≤ 100)과 L (1 ≤ L ≤ N)이 주어진다. 둘째 줄부터 N개의 줄에 지도가 주어진다. 각 칸의 높이는 10보다 작거나 같은 자연수이다.

www.acmicpc.net

 

풀이

길을 지나갈 수 있으려면 길에 속한 모든 칸의 높이가 모두 같아야 한다. 또는 경사로를 놓을 수 있는 조건을 만족해야 한다.

지나갈 수 있는 길의 개수를 구하기 위해서 먼저 행별로 탐색한 후 열별로 탐색한다.

열별로 탐색할 때는 원래 지도의 전치행렬을 만들어서 탐색한다.

    private static int n, l;

    public static void main(String[] args) throws IOException {
    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringTokenizer st = new StringTokenizer(br.readLine());
    	
    	n = Integer.parseInt(st.nextToken());
    	l = Integer.parseInt(st.nextToken());
    	
    	int[][] map = new int[n][n];
    	
    	for (int i = 0; i < n; i++) {
    		st = new StringTokenizer(br.readLine());
    		for (int j = 0; j < n; j++) {
    			map[i][j] = Integer.parseInt(st.nextToken());
    		}
    	}
    	
    	int cnt = 0;
    	cnt += searchMap(map);
    	
    	// 지도의 전치행렬 생성
    	int[][] transposeMap = new int[n][n];
    	for (int i = 0; i < n; i++) {
    		for (int j = 0; j < n; j++) {
    			transposeMap[i][j] = map[j][i];
    		}
    	}
    	
    	cnt += searchMap(transposeMap);
    	
    	System.out.println(cnt);
    }

 

int searchMap(int[][] map)

지도를 행별로 탐색하여 지나갈 수 있는 길의 개수를 구한다.

각 행을 탐색할 때 경사로 설치 여부를 저장하는 boolean[] stairs를 생성하고, 경사로를 놓을 수 있는 경우 makeStairs() 메서드를 호출하여 경사로를 놓는다.

    private static int searchMap(int[][] map) {
    	int cnt = 0;
    	for (int i = 0; i < n; i++) {
    		int first = map[i][0];
    		boolean flag = true;
    		boolean[] stairs = new boolean[n];
    		
    		for (int j = 1; j < n; j++) {
    			if (first != map[i][j]) { // 경사로에 높이 차가 생기는 경우
    				if (first == map[i][j]+1) {
    					// 범위를 벗어나는 경우
    					if (j + l > n) {
    						flag = false;
        					break;
    					}
    					
    					// L개의 연속된 칸의 높이가 모두 같아야 하며, 이미 계단이 놓여져 있지 않아야 경사로를 놓을 수 있다.
    					// 같지 않거나 계단이 이미 있으면 flag를 false로 변경 후, break
    					int[] copyMap = Arrays.copyOfRange(map[i], j, j+l);
    					boolean[] copyStairs = Arrays.copyOfRange(stairs, j, j+l);
    					if (Arrays.stream(copyMap).distinct().count() != 1 || isStair(copyStairs)) {
    						flag = false;
        					break;
    					}
    					// 경사로를 놓고, first와 j 값 업데이트
    					makeStairs(stairs, j, j+l);
    					first = map[i][j];
    					j = j+l-1;
    				}
    				else if (first + 1 == map[i][j]) {
    					// 범위를 벗어나는 경우
    					if (j - l < 0) {
    						flag = false;
        					break;
    					}
    					
    					// L개의 연속된 칸의 높이가 모두 같아야 하며, 이미 계단이 놓여져 있지 않아야 경사로를 놓을 수 있다.
    					// 같지 않거나 계단이 이미 있으면 flag를 false로 변경 후, break
    					int[] copyMap = Arrays.copyOfRange(map[i], j-l, j);
    					boolean[] copyStairs = Arrays.copyOfRange(stairs, j-l, j);
    					if (Arrays.stream(copyMap).distinct().count() != 1 || isStair(copyStairs)) {
    						flag = false;
        					break;
    					}
    					
    					// 경사로를 놓고, first 값 업데이트
    					makeStairs(stairs, j-l, j);
    					first = map[i][j];
    				}
    				else { // 낮은 칸과 높은 칸의 높이 차이가 1이 아닌 경우
    					flag = false;
    					break;
    				}
    			}
    		}
    		
    		if (flag) { // 지나갈 수 있는 길인 경우
    			cnt++;
    		}
    	}
    	
    	return cnt;
    }

 

boolean isStair(boolean[] stairs)

주어진 stairs 배열에 경사로가 있으면 true를 리턴, 경사로가 없다면 false를 리턴한다.

void makeStairs(boolean[] stairs, int start, int end)

start부터 end-1까지 경사로를 설치한다. 즉, stairs[i]를 true로 변경한다.

    private static boolean isStair(boolean[] stairs) {
    	for (int i = 0; i < stairs.length; i++) {
    		if (stairs[i]) {
    			return true;
    		}
    	}
    	return false;
    }
    
    private static void makeStairs(boolean[] stairs, int start, int end) {
    	for (int i = start; i < end; i++) {
    		stairs[i] = true;
    	}
    }

전체 코드

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

public class Main {
	
	private static int n, l;

    public static void main(String[] args) throws IOException {
    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringTokenizer st = new StringTokenizer(br.readLine());
    	
    	n = Integer.parseInt(st.nextToken());
    	l = Integer.parseInt(st.nextToken());
    	
    	int[][] map = new int[n][n];
    	
    	for (int i = 0; i < n; i++) {
    		st = new StringTokenizer(br.readLine());
    		for (int j = 0; j < n; j++) {
    			map[i][j] = Integer.parseInt(st.nextToken());
    		}
    	}
    	
    	int cnt = 0;
    	cnt += searchMap(map);
    	
    	// 지도의 전치행렬 생성
    	int[][] transposeMap = new int[n][n];
    	for (int i = 0; i < n; i++) {
    		for (int j = 0; j < n; j++) {
    			transposeMap[i][j] = map[j][i];
    		}
    	}
    	
    	cnt += searchMap(transposeMap);
    	
    	System.out.println(cnt);
    }
    
    private static int searchMap(int[][] map) {
    	int cnt = 0;
    	for (int i = 0; i < n; i++) {
    		int first = map[i][0];
    		boolean flag = true;
    		boolean[] stairs = new boolean[n];
    		
    		for (int j = 1; j < n; j++) {
    			if (first != map[i][j]) { // 경사로에 높이 차가 생기는 경우
    				if (first == map[i][j]+1) {
    					// 범위를 벗어나는 경우
    					if (j + l > n) {
    						flag = false;
        					break;
    					}
    					
    					// L개의 연속된 칸의 높이가 모두 같아야 하며, 이미 계단이 놓여져 있지 않아야 한다.
    					// 같지 않거나 계단이 이미 있으면 flag를 false로 변경 후, break
    					int[] copyMap = Arrays.copyOfRange(map[i], j, j+l);
    					boolean[] copyStairs = Arrays.copyOfRange(stairs, j, j+l);
    					if (Arrays.stream(copyMap).distinct().count() != 1 || isStair(copyStairs)) {
    						flag = false;
        					break;
    					}
    					// 계단을 세우고, first와 j 값 업데이트
    					makeStairs(stairs, j, j+l);
    					first = map[i][j];
    					j = j+l-1;
    				}
    				else if (first + 1 == map[i][j]) {
    					// 범위를 벗어나는 경우
    					if (j - l < 0) {
    						flag = false;
        					break;
    					}
    					
    					// L개의 연속된 칸의 높이가 모두 같아야 하며, 이미 계단이 놓여져 있지 않아야 한다.
    					// 같지 않거나 계단이 이미 있으면 flag를 false로 변경 후, break
    					int[] copyMap = Arrays.copyOfRange(map[i], j-l, j);
    					boolean[] copyStairs = Arrays.copyOfRange(stairs, j-l, j);
    					if (Arrays.stream(copyMap).distinct().count() != 1 || isStair(copyStairs)) {
    						flag = false;
        					break;
    					}
    					
    					// 계단을 세우고, first 값 업데이트
    					makeStairs(stairs, j-l, j);
    					first = map[i][j];
    				}
    				else { // 낮은 칸과 높은 칸의 높이 차이가 1이 아닌 경우
    					flag = false;
    					break;
    				}
    			}
    		}
    		
    		if (flag) { // 계단을 놓는 경우
    			cnt++;
    		}
    	}
    	
    	return cnt;
    }
    
    private static boolean isStair(boolean[] stairs) {
    	for (int i = 0; i < stairs.length; i++) {
    		if (stairs[i]) {
    			return true;
    		}
    	}
    	return false;
    }
    
    private static void makeStairs(boolean[] stairs, int start, int end) {
    	for (int i = start; i < end; i++) {
    		stairs[i] = true;
    	}
    }
    
}

 

수정한 풀이

searchMap()을 호출하여 2차원 배열을 인자로 넘기는 대신, 2차원 배열의 한 행을 인자로 넘겨 각 행에 대해 탐색하도록 한다. 메서드 명도 searchMap()에서 searchOneLine()으로 변경했다.

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

public class Main {
	
	private static int n, l;

    public static void main(String[] args) throws IOException {
    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringTokenizer st = new StringTokenizer(br.readLine());
    	
    	n = Integer.parseInt(st.nextToken());
    	l = Integer.parseInt(st.nextToken());
    	
    	int[][] map = new int[n][n];
    	
    	for (int i = 0; i < n; i++) {
    		st = new StringTokenizer(br.readLine());
    		for (int j = 0; j < n; j++) {
    			map[i][j] = Integer.parseInt(st.nextToken());
    		}
    	}
    	
    	// 지도의 전치행렬 생성
    	int[][] transposeMap = new int[n][n];
    	for (int i = 0; i < n; i++) {
    		for (int j = 0; j < n; j++) {
    			transposeMap[i][j] = map[j][i];
    		}
    	}
    	
    	int cnt = 0;
    	
    	for (int i = 0; i < n; i++) {
    		int[] copyMap = Arrays.copyOf(map[i], n);
    		if(searchOneLine(copyMap))
    			cnt++;
    		copyMap = Arrays.copyOf(transposeMap[i], n);
    		if(searchOneLine(copyMap))
    			cnt++;
    	}
    	
    	System.out.println(cnt);
    }
    
    private static boolean searchOneLine(int[] map) {
    	boolean[] stairs = new boolean[n]; // 경사로 설치 여부
    		
    	for (int j = 1; j < n; j++) {
    		int diff = map[j-1] - map[j];
    		
    		if (diff > 1 || diff < -1) return false;
    		
    		if (diff == 1) {
    			// 범위를 벗어나는 경우
    			if (j + l > n) {
    				return false;
    			}
    					
    			// L개의 연속된 칸의 높이가 모두 같아야 하며, 이미 계단이 놓여져 있지 않아야 한다.
    			// 같지 않거나 계단이 이미 있으면 false를 리턴한다.
    			int[] copyMap = Arrays.copyOfRange(map, j, j+l);
    			boolean[] copyStairs = Arrays.copyOfRange(stairs, j, j+l);
    			if (Arrays.stream(copyMap).distinct().count() != 1 || isStair(copyStairs)) {
    				return false;
    			}
    			// 경사로를 놓고, j 값 업데이트
    			makeStairs(stairs, j, j+l);
    			j = j+l-1;
    		}
    		else if (diff == -1) {
    			// 범위를 벗어나는 경우
    			if (j - l < 0) {
    				return false;
    			}
    				
    			// L개의 연속된 칸의 높이가 모두 같아야 하며, 이미 계단이 놓여져 있지 않아야 한다.
    			// 같지 않거나 계단이 이미 있으면 false를 리턴한다.
    			int[] copyMap = Arrays.copyOfRange(map, j-l, j);
    			boolean[] copyStairs = Arrays.copyOfRange(stairs, j-l, j);
    			if (Arrays.stream(copyMap).distinct().count() != 1 || isStair(copyStairs)) {
    				return false;
    			}
    				
    			// 경사로 놓기
    			makeStairs(stairs, j-l, j);
    		}
    	}
    		
    	return true;
    }
    
    private static boolean isStair(boolean[] stairs) {
    	for (int i = 0; i < stairs.length; i++) {
    		if (stairs[i]) {
    			return true;
    		}
    	}
    	return false;
    }
    
    private static void makeStairs(boolean[] stairs, int start, int end) {
    	for (int i = start; i < end; i++) {
    		stairs[i] = true;
    	}
    }
    
}

 

Reference (다른 풀이)

 

728x90
profile

Seren dev's blog

@Seren dev

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!