[문제링크]

 

9935번: 문자열 폭발

첫째 줄에 문자열이 주어진다. 문자열의 길이는 1보다 크거나 같고, 1,000,000보다 작거나 같다. 둘째 줄에 폭발 문자열이 주어진다. 길이는 1보다 크거나 같고, 36보다 작거나 같다. 두 문자열은 모

www.acmicpc.net

 

0. 폭탄 진행현황을 index로 검사한다

 

1. 현재 index에 맞는 문자가 들어오면 : 누적 후 index+1

 

2. 현재 index와 다른 문자가 들어오면

  - 폭탄의 첫 문자이다 : 새 폭탄의 시작점일 가능성, 현재 index정보를 백업하고 누적, index=1부터 다시 시작

  - 일반 문자이다 : 폭탄이 아니므로 모든 index를 제거, 누적된 문자들을 출력 문자열에 추가하고 index=0

  - 폭탄의 마지막 문자이다 : 폭탄이 터진다. 누적한 문자를 제거하고 백업한 index복구, 없으면 index=0

 

3. 모든 문자를 순회 후 : 누적한 문자가 있다면 출력 문자열에 추가

 

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

public class Main{
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		StringBuilder sb2;
		
		String s = br.readLine();
		String boom = br.readLine();
		
		int idx=0;
		Stack<Character> charStack = new Stack<>();
		Stack<Integer> idxStack = new Stack<>();
		
		for (int i = 0; i < s.length(); i++) {
			char cur = s.charAt(i);
			
			if(cur==boom.charAt(idx)) {
				//폭탄이 순조롭게 진행중
				idx++;
				charStack.add(cur);
				if(idx == boom.length()) {
					//폭탄의 완성
					//charStack에서 완성한 boom 비우기
					
					for (int j = 0; j < idx; j++) {
						charStack.pop();
					}
					//idx가 존재한다면, 복구하기
					if(!idxStack.isEmpty()) {
						idx = idxStack.pop();
					}else {
						idx = 0;
					}
				}
			}
			else {
				if(cur==boom.charAt(0)) {
					//새 폭탄의 시작
					idxStack.add(idx);
					charStack.add(cur);
					idx=1;
				}
				else {
					//평범한 문자열일 경우
					//쌓은 idx 다비우고
					idxStack.clear();
					
					//쌓인 char들은 boom이 아니므로 다 넣는다
					sb2 = new StringBuilder();
					while(!charStack.isEmpty()) {
						sb2.append(charStack.pop());
					}sb.append(sb2.reverse());
					//마지막에 현재 문자 반영
					sb.append(cur);
					idx=0;
				}
			}
		}
		sb2 = new StringBuilder();
		while(!charStack.isEmpty()) {
			sb2.append(charStack.pop());
		}sb.append(sb2.reverse());
		if("".equals(sb.toString())) System.out.println("FRULA");
		else System.out.println(sb);
        
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

'알고리즘 문제 풀이 > BOJ 골드' 카테고리의 다른 글

[백준] 15961 - 회전 초밥  (0) 2021.04.15
[백준] 2638 - 치즈  (0) 2021.04.15
[백준] 15686 - 치킨 배달  (0) 2021.04.15
[백준] 1019 - 책 페이지  (0) 2021.04.13
[백준] 1566 - P배열  (0) 2021.04.13
[백준] 12865 - 평범한 배낭  (0) 2021.04.12
[백준] 1504 - 특정한 최단 경로  (0) 2021.04.12

[문제링크]

 

13137번: Exchange Problem

만약 병찬이가 사용한 방법이 항상 최적이라면 'Yes'를 출력하고, 그렇지 않다면 'No'를 출력한다.

www.acmicpc.net

 

0. 그리디를 이용해 가격 구하기

  - n번 동전의 가치가 w이고, n-1번 동전까지 사용하여 w-1 금액까지는 옳은 해가 구해져 있다면

  - w원 이후의 가격 x에 대해선 ( (x%w)의 최적해 + (x/w) ) 이 최적해이다

  - ex) 한국 동전에 대해, w가 500원일때 650원의 최적해는 (150원의 최적해 + 1) 이다

  - DP는 이 문제에서 항상 옳은 해를 구할 수 있다

  - DP를 이용해 구한 해와 그리디를 이용해 구한 해가 일치한다면, 그리디가 최적해를 구하는 것

  - 그리디를 통해 w ~ 2*w까지 최적해를 구할수 있다고 하면, 2*w ~ 이후에 대해서도 최적해가 보장된다

  - n+1번째 동전의 가치가 2*w보다 작다면 n+1번 동전까지만 최적해를 증명해도 된다

  - 즉, n번째 동전에 대해, min( 2*w(n) , w(n+1) ) 까지 최적해 여부를 검증

 

1. 정답은 기본값 Yes로 두고, 모든 동전에 대해 최적해 일치 여부를 검사한다

 

2. 현재 금액 i가 n번 코인의 화폐가치 w보다 작을 경우, w까지 진행한다

 

3. w부터 min( w*2, w[n+1] ) 금액까지 그리디 방식으로 해를 만든다

 

4. w부터 min( w*2, w[n+1] ) 금액까지 DP방식으로 해를 만들며, 그리디의 해와 비교한다

  - 중간에 불일치하는 값이 존재하면, 답을 No로 바꾸고, break한다

 

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

public class Main {
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int N = pint(br.readLine());
		int[] coin = new int[N];
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		for (int i = 0; i < N; i++) {
			coin[i]=pint(st.nextToken());
		}
		int[] valid = new int[coin[N-1]*2+1];//최대 20만 1
		valid[1]=1;//1원은 항상 1.
		
		String answer = "Yes";
		
		int coinIdx=1;
		for (int i = 1; i < coin[N-1]*2+1 && coinIdx<N; i++) {

			i = Math.min(2*i-1, coin[coinIdx]-1);
			//coin[i]번의 화폐가치까지 정상진행
			while(i<coin[coinIdx]) {
				int realcosti=Integer.MAX_VALUE;
				for (int k = 0; k < coinIdx; k++) {
					if(1 + valid[i-coin[k]] < realcosti)realcosti=1 + valid[i-coin[k]];
				}valid[i++]=realcosti;
			}
			
			//valid[i] ~ 2 i까지 그리디로, +1해서 제작
			int destination = i*2;
			if(coinIdx<N-1)destination = Math.min(i*2, coin[coinIdx+1]);
			for (int j = i; j <= destination; j++) {
				valid[j]=valid[j-i]+1;
			}
			
			//직접 계산해가면서 valid[j]와 계산값이 같은지 비교. 다르면 바로 탈출
			//i-1번까지의 동전만 사용해서 i ~ 2*i의 값들을 계산해보기
			for (int j = i; j <= destination; j++) {
				int realcosti=Integer.MAX_VALUE;
				for (int k = 0; k <= coinIdx; k++) {
					if(1 + valid[j-coin[k]] < realcosti)realcosti=1 + valid[j-coin[k]];
				}
				if(realcosti != valid[j]) {
					answer = "No";
					i=coin[N-1]*2+1;//for문 종료 목적
					break;
				}
			}
			coinIdx++;
		}
		System.out.println(answer);
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

'알고리즘 문제 풀이 > BOJ 플래 이상' 카테고리의 다른 글

[백준] 5373 - 큐빙  (0) 2021.05.05

[문제링크]

 

5639번: 이진 검색 트리

트리를 전위 순회한 결과가 주어진다. 노드에 들어있는 키의 값은 106보다 작은 양의 정수이다. 모든 값은 한 줄에 하나씩 주어지며, 노드의 수는 10,000개 이하이다. 같은 키를 가지는 노드는 없다

www.acmicpc.net

 

0. bufferedreader로 EOF 입력받는법 : null인지 아닌지 체크하기

 

1. 모든 수를 입력받아서 list로 저장

 

2. 전위순회의 결과물이므로 [루트] [왼쪽 서브트리] [오른쪽 서브트리] 의 형태로 나눌 수 있다.

 

3. 루트보다 커지는 지점이 오른쪽 서브트리의 시작점이므로, [왼쪽 서브트리] > [오른쪽 서브트리] > [루트] 의 순서로 재귀를 실행한다

 

4. 인자로 받은 서브트리가 1칸짜리면 그 원소를 list에 넣고 반환한다

  - 루트는 1칸짜리라 재귀 실행 = list에 자신 저장이므로 재귀 호출 대신 직접 넣는다

 

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

public class Main{
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		String s;
		num = new ArrayList<>();
		back = new ArrayList<>();
		
		while((s=br.readLine())!=null) {
			num.add(pint(s));
		}
		
		rec(0,num.size()-1);
		
		for (int i = 0; i < back.size(); i++) {
			System.out.println(back.get(i));
		}
		
	}
	static ArrayList<Integer>num;
	static ArrayList<Integer>back;
	
	static void rec(int s, int e) {
		if(s==e) {
			back.add(num.get(s));
			return;
		}
		
		int root = num.get(s);
		int cnt=s+1;
		while(cnt<=e && num.get(cnt)<root)cnt++;
		
		if(s+1<=cnt-1)rec(s+1, cnt-1);
		if(cnt<=e)rec(cnt,e);
		back.add(root);
	}
	
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

'알고리즘 문제 풀이 > BOJ 실버' 카테고리의 다른 글

[백준] 17276 - 배열 돌리기  (0) 2021.10.10
[백준] 1325 - 효율적인 해킹  (0) 2021.09.25
[백준] 5567 - 결혼식  (0) 2021.08.08
[백준] 14241 - 슬라임 합치기  (0) 2021.07.07
[백준] 1697 - 숨바꼭질  (0) 2021.05.29
[백준] 2564 - 경비원  (0) 2021.04.13
[백준] 2110 - 공유기 설치  (0) 2021.04.13

[문제링크]

 

1019번: 책 페이지

첫째 줄에 0이 총 몇 번 나오는지, 1이 총 몇 번 나오는지, ..., 9가 총 몇 번 나오는지를 공백으로 구분해 출력한다.

www.acmicpc.net

 

* 요약하자면 y번째 자리에 x번 수가 있을때

  - y자릿수를 만드는데 필요한 index를 x번 가산 ( 1 ~ y-1 자리에 등장하는 수 처리 )

  - 앞에서 등장한 prev 숫자들을 x*y번 가산 ( y+1 ~ 자리에 등장하는 수 처리 )

  - x보다 작은 수들을 y자릿수씩 가산 ( y 자리에 등장하는 수 처리 )

  - 3부분으로 나눠 처리하는 방법이다

 

0. 10단위로, 그 아랫 페이지까지 나오는 0~9의 갯수를 미리 계산해 저장한다

  - 1000페이지 미만까지 나오는 숫자는, 100페이지 미만에서 나오는 숫자들이 10회 반복해서 나오고

    + 1~9(앞자리)가 각 100번씩 나온다

  - 계산의 편의를 위해 0 또한 앞자리로 존재한다고 가정하고 연산, 마지막에 제거한다

 

1. 앞에서부터 숫자와 자릿수를 추출한다 ( cur, len )

 

2. len에 해당하는 index의 값을, cur번 더해준다 ( 

  - ex) 543에서 5를 처리할 때 : 5와 3(100의 자릿수)을 추출, index의 3번째(100까지 나오는 숫자) 배열을 5회 가산

 

3. prev배열은 앞에서 등장한 숫자 정보를 가지고 있으며, 현재 자리에서 반복하는 횟수만큼 가산된다

  - ex) 543에서 4를 처리할 때 : 5는 40회 가산되어야한다

 

4. 현재 cur에 대해, 0~cur-1까지의 숫자는 자릿수만큼 등장하므로, 가산해준다

  - ex) 543에서 4를 처리할 때, 0,1,2,3은 10번씩 등장할 것이다

 

5. 마지막 자리를 처리할때는, prev배열을 1회 추가로 가산해야 한다

  - 543에서 4를 처리할 때는 prev배열을 50X, 51X, 52X, 53X에 대해 4 * 10회 가산해주고,

  - 54X에 대한 처리는 X가 불확실하므로 아래 자릿수에서 하게 된다

  - 하지만 마지막 자릿수인 3에선 불확실한 수가 없으므로 540, 541, 542, 543 총 4 * 1회 해주게 된다

 

6. 맨 앞에 등장한 0을 제거한다.

  - 가장 앞의 0은 1의 자릿수에선 1번, 10의 자릿수에선 10번, 100의 자릿수에선 100번 등장한다.

  - ex) 543은 100의 자릿수이므로, 총 111번의 0이 등장한다

  - 주어진 수의 자릿수까지 1, 10, 100을 계속 빼준다

 

7. 나중에 다시 보기위해 작성한 설명인데, 미래의 내가 이걸 알아들을지 자신이 없다

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

public class Main{
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		long[]page = new long[10];
		long[]prev = new long[10];
		long[]ans = new long[10];
		
		ArrayList<long[]>index=new ArrayList<>();
		index.add(page.clone());
		int cnt=1;
		//전처리
		for (int i = 0; i <= 9; i++) {
			for (int j = 0; j <= 9; j++) {
				page[j]*=10;
				page[j]+=cnt;
			}
			index.add(page.clone());
			cnt*=10;
		}

		String N = br.readLine();
		int len = N.length();
		
		//0번 자리부터
		for (int i = 0; i < N.length(); i++, len--) {
			int cur = N.charAt(i)-'0';

			long[] curIdx = index.get(len-1);
			long repeat = (long)Math.pow(10, len-1);
			for (int j = 0; j <= 9; j++) {
				ans[j]+=curIdx[j]*cur;
				ans[j]+=prev[j]*repeat*cur;//prev처리
			}
			
			//가장 앞자리 처리
			for (int j = 0; j < cur; j++) {
				ans[j]+=repeat;
			}
			
			prev[cur]++;
		}
		for (int j = 0; j <= 9; j++) ans[j]+=prev[j]; // prev배열 추가 1회 처리
		for (int i = 0; i < N.length(); i++) ans[0]-=Math.pow(10, i); // 맨 앞에 등장한 0 처리
		for (int i = 0; i <= 9; i++) System.out.print(ans[i]+" ");
		
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

 

[문제링크]

 

2564번: 경비원

첫째 줄에 블록의 가로의 길이와 세로의 길이가 차례로 주어진다. 둘째 줄에 상점의 개수가 주어진다. 블록의 가로의 길이와 세로의 길이, 상점의 개수는 모두 100이하의 자연수이다. 이어 한 줄

www.acmicpc.net

 

0. 블록의 길이는 n*m이며 블록 중간에는 상점도 길도 없으므로 한바퀴 도는 경로를 n+m+n+m크기의 1차원 배열로 관리할 수 있다

 

1. 북쪽 > 동쪽 > 남쪽 > 서쪽 순서의 경로를 가정하고, 입력받은 상점의 위치를 가공해 저장한다

 

2. 마지막에 시작점을 입력받고, 배열을 한바퀴 순회(배열의 범위를 넘어가면 0으로 초기화)하며 거리를 누적한다

  - 거리는 정방향(i)과 역방향(totalLen - i) 중 짧은쪽을 누적한다

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
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 = new StringTokenizer(br.readLine());
		int n = pint(st.nextToken());
		int m = pint(st.nextToken());
		
		int[] map = new int[(n+m)*2];
		int store = pint(br.readLine());
		int pos=0;
		int totalCost=0; //최소 코스트 
		int totalLen = (n+m)*2; // 상점가 블록 전체의 갯수
		
		for (int i = 0; i <= store; i++) {
			int temp=0;
			st = new StringTokenizer(br.readLine());
			switch (st.nextToken()) {
			case "1"://북쪽
				temp=pint(st.nextToken());break;
			case "2"://남쪽
				temp=n+m+n-pint(st.nextToken());break;
			case "3"://서쪽
				temp=(n+m)*2-pint(st.nextToken());break;
			case "4"://동쪽
				temp=n+pint(st.nextToken());break;
			default: break;
			}
			if(i==store)pos=temp; // 마지막 입력은 시작 위치
			map[temp]=1;
		}
		for (int i = 1; i < totalLen; i++) {
			if(pos+i==totalLen)pos=-i;
			if(map[pos+i]==1) {
				totalCost+=Math.min(i, totalLen-i);
			}
		}System.out.println(totalCost);
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

2110번: 공유기 설치

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가

www.acmicpc.net

 

0. 집에 n개의 공유기를 설치할 때, 가능한 최대 거리를 구하는 문제

  - 집 사이의 간격에 대해 바이너리서치 진행

 

1. 바이너리 서치의 시작점은 0, 끝점은 가장 먼 집의 좌표

 

2. 구한 dis에 따라, 최대한 그리디하게 집에 공유기를 설치했을 때의 갯수를 센다

 

3-1. 공유기가 목표 갯수를 충족했다면, ans를 갱신 후 min값을 갱신, 더 큰 dis를 시도해본다

3-1. 공유기가 목표 갯수에 미달했다면, max값을 갱신, 더 작은 dis를 시도해본다

 

4. min과 max가 교차하면 종료, 구한 ans값을 출력한다 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
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 = new StringTokenizer(br.readLine(), " ");
		int n = pint(st.nextToken());
		int m = pint(st.nextToken());
		int[]house = new int[n];
		for (int i = 0; i < n; i++) {
			house[i]=pint(br.readLine());
		}
		Arrays.sort(house);
		
		int min=0, max=house[n-1];
		int ans=0;
		while(min<=max) {
			int dis = (max+min)/2;
			
			int prev_house = house[0];
			int cnt=1;
			for (int i = 0; i < n; i++) {
				if(prev_house + dis <= house[i]) {
					prev_house=house[i];
					cnt++;
				}
			}
			if(cnt>=m) {
				ans=dis;
				min=dis+1;
				
			}else {
				max=dis-1;
			}
		}
		System.out.println(ans);
		
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

1566번: P배열

정수로 이루어진 2차원 배열이 P배열이 되려면, 각각의 열에 있는 원소의 합과, 행에 있는 원소의 합이 모두 0보다 커야 한다. 예를 들어, 2 1 -1 -1 2 2 는 P배열이지만, 1 1 -1 -1 2 2 는 P배열이 아니다.

www.acmicpc.net

0. reverseRow : 행을 뒤집고, rowSum/colSum을 갱신하는 함수

  - reverseCol : 열을 뒤집고, rowSum/colSum을 갱신하는 함수

  - toOrigin : 뒤집었던 열(t2변수에 bitmask로 저장됨)들을 복구하는 함수 

  - findmin : 부분집합을 만들고, 열을 뒤집고, 행을 검사하는 함수

 

1. 배열의 모든 행에 대해, 모든 가능한 부분집합을 만들어 reverse한다

 

2. 1번의 모든 경우에 대해, 값이 음수인 모든 열을 뒤집어본다

  - 값이 0인 열이 있다면 뒤집어도 0이므로, 양수가 될수 없으니 즉시 원상복귀 후 return한다

 

3. 2번을 통해 모든 열이 양수가 된 후에도 모든 행이 양수를 유지하고 있다면, 옳은 P배열이다

  - min값 갱신

 

4. min의 최댓값은 (N+M)/2이므로, (N+M)/2+1을 초깃값으로 정한다

  - ( N, M은 18 이하이므로 19 이상의 임의의 수를 사용해도 문제 없다 )

  - 동일한 값을 유지한다면 P배열을 만드는게 불가능했단 의미로, -1을 출력한다

  - 만드는게 가능했다면 구한 min값을 출력한다

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
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 =new StringTokenizer(br.readLine());

		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		map=new int[N][M];
		rowSum = new int[N];
		colSum = new int[M];
		min=(N+M)/2+1;
		
		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < M; j++) {
				map[i][j]=Integer.parseInt(st.nextToken());
				colSum[j]+=map[i][j];
				rowSum[i]+=map[i][j];
			}
		}
		findmin(0, 0);
		
		if(min==(N+M)/2+1)System.out.println(-1);
		else System.out.println(min);
		
	}
	static int[] rowSum;//행 합계
	static int[] colSum;//열 합계
	static int[][]map;
	static int N,M,min;
	
	static void findmin(int cnt, int colChk) {
		if(cnt==M) {
			//행을 뒤집은 부분집합 완성
			int temp=0, temp2=0;
			for (int i = 0; i < N; i++) {
				if(rowSum[i]==0) {
					toOrigin(temp2);
					return;
				}
				else if(rowSum[i]<0) {
					reverserow(i);
					temp++;
					temp2 = temp2|1<<i;
				}
			}
			for (int i = 0; i < M; i++) {
				if(colSum[i]<=0) {
					toOrigin(temp2);
					return;
				}
			}
			min=min<colChk+temp?min:colChk+temp;
			toOrigin(temp2);
			
			return;
		}
		
		//안선택
		findmin(cnt+1,colChk);
		//선택
		reversecol(cnt);
		findmin(cnt+1,colChk+1);
		reversecol(cnt);
		
		
	}
	static void toOrigin(int t2) {
		for (int i = 0; i < N; i++)if((t2&1<<i)!=0)reverserow(i);
	}
	
	static void reverserow(int idx) {
		for (int i = 0; i < M; i++) {
			map[idx][i] =-map[idx][i];
			colSum[i] = colSum[i] +map[idx][i]*2; 
		}
		rowSum[idx]*=-1;
	}
	static void reversecol(int idx) {
		for (int i = 0; i < N; i++) {
			map[i][idx]=-map[i][idx];
			rowSum[i] = rowSum[i] +map[i][idx]*2; 
		}
		colSum[idx]*=-1;
	}
	
	
}

결과 화면

[문제링크]

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com

[문제링크]

 

14890번: 경사로

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

www.acmicpc.net

 

 

0. 활주로 건설이 불가능한 경우는 2가지이다

  - 2칸 이상 차이가 나는 경우

  - 1칸 차이가 나지만 X칸만큼의 공간이 존재하지 않을 경우

 

1. 2칸 이상 차이가 난다면 불가능 처리한다

 

2. 높이가 동일한 경우, cnt로 갯수를 세가며 진행한다

  - 올라가야하는 상황이 생겼을 때, cnt가 X보다 크거나 같아야만 진행 가능하다

  - 올라간 칸에서부터 시작하므로 cnt값을 1로 초기화

 

3. 내려가야하는 상황이 생겼다면 앞에 X칸의 공간이 동일한 높이로 존재해야 진행 가능하다

  - 반목문으로 X칸의 높이를 확인, 다르면 불가능 처리한다

  - 전부 같다면, 현재 위치가 j였을때 j+X칸에서부터 다시 시작하므로, j+X-1으로 포인터를 옮긴다

  - 이때, j+X-1칸은 경사로의 마지막 칸이므로, cnt는 0으로 초기화

 

4. 위 과정을 모든 행/열에 대해 실행해주고 가능한 경우를 카운트

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

public class Solution{
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		
		int tc = pint(br.readLine());
		for (int testcase = 1; testcase <= tc; testcase++) {

			StringTokenizer st = new StringTokenizer(br.readLine(), " ");
			int n = pint(st.nextToken());
			int x = pint(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]=pint(st.nextToken());
				}
			}
			
			int possibleCnt=0;
			
			for (int i = 0; i < n; i++) {
				//i번째 Row의 불가능 가능 여부를 탐색
				boolean isP = true;
				
				//1. 2칸 이상 차이나면 불가
				for (int j = 1; j < n; j++) {
					if(Math.abs(map[i][j] - map[i][j-1]) >=2)isP=false;
				}if(!isP)continue;
				
				//2. 1칸 올라|내려 가야하는데, 뒤|앞에 공간이 x칸 없으면 불가
				int prev=map[i][0];
				int cnt=1;
				for (int j = 1; j < n; j++) {
					//같으면 +
					if(prev == map[i][j])cnt++;
					else if(prev< map[i][j]) {
						//올라갈 때
						if(cnt>=x) {
							//ok
						}
						else {
							isP=false;
						}
						prev=map[i][j];
						cnt=1;//cnt초기화
					}
					else {
						//내려갈 때
						//앞에 x칸이 다 같은 높이로 존재하는지 확인
						//만족한다면, x 앞칸으로 포인터(j)이동
						prev = map[i][j];
						cnt=1;
						for (int j2 = 1; j2 < x; j2++) {
							if(j+j2 >= n)break;
							if(prev==map[i][j+j2])cnt++;
						}
						if(cnt!=x)isP=false;
						j = j+x-1;
						cnt=0;//cnt초기화
					}
				}
				if(isP)possibleCnt++;
			}
			
			for (int i = 0; i < n; i++) {
				//i번째 Col의 불가능 가능 여부를 탐색
				boolean isP = true;
				
				//1. 2칸 이상 차이나면 불가
				for (int j = 1; j < n; j++) {
					if(Math.abs(map[j][i] - map[j-1][i]) >=2)isP=false;
				}if(!isP)continue;
				
				//2. 1칸 올라|내려 가야하는데, 뒤|앞에 공간이 x칸 없으면 불가
				int prev=map[0][i];
				int cnt=1;
				for (int j = 1; j < n; j++) {
					//같으면 +
					if(prev == map[j][i])cnt++;
					else if(prev< map[j][i]) {
						//올라갈때
						if(cnt>=x) {
							//ok
						}
						else {
							isP=false;
						}
						prev=map[j][i];
						cnt=1;//cnt초기화
					}
					else {
						//내려갈 때
						//앞에 x칸이 다 같은 높이로 존재하는지 확인
						//만족한다면, x 앞칸으로 포인터(j)이동
						prev = map[j][i];
						cnt=1;
						for (int j2 = 1; j2 < x; j2++) {
							if(j+j2 >= n)break;
							if(prev==map[j+j2][i])cnt++;
						}
						if(cnt!=x)isP=false;
						j = j+x-1;
						cnt=0;
					}
					
				}
				if(isP)possibleCnt++;
			}
			
			sb.append("#").append(testcase).append(" ").append(possibleCnt).append("\n");
		}
		System.out.println(sb);
		
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

'알고리즘 문제 풀이 > SWEA' 카테고리의 다른 글

[SWEA] 2115 - 벌꿀채취  (0) 2021.04.22
[SWEA] 8382 - 방향전환  (0) 2021.04.19
[SWEA] 8458 - 원점으로 집합  (0) 2021.04.19
[SWEA] 1953 - 탈주범검거  (0) 2021.04.15
[SWEA] 5656 - 벽돌깨기  (0) 2021.04.15
[SWEA] 1249 - 보급로  (0) 2021.04.12
[SWEA] 5644 - 무선충전  (0) 2021.04.12

+ Recent posts