[문제링크]

 

14496번: 그대, 그머가 되어

첫째 줄에 머호가 바꾸려 하는 문자 a와 b가 주어진다. 둘째 줄에 전체 문자의 수 N과 치환 가능한 문자쌍의 수 M이 주어진다. (1 ≤ N ≤ 1,000, 1 ≤ M ≤ 10,000) 이후 M개의 줄에 걸쳐 치환 가능한 문

www.acmicpc.net

 

0. a-b 두 노드간 최단 거리 구하기

 

1. 다익스트라, 벨만 포드 등 다양하게 풀이 가능하다

 

2. bfs로 탐색, 목표 노드가 발견되는 즉시 탈출

 

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 = new StringTokenizer(br.readLine(), " ");
		int a = pint(st.nextToken())-1;
		int b = pint(st.nextToken())-1;
		
		st = new StringTokenizer(br.readLine(), " ");
		int n = pint(st.nextToken());
		int m = pint(st.nextToken());
		
		ArrayList<ArrayList<Integer>> adjList = new ArrayList<>();
		for (int i = 0; i < n; i++) {
			adjList.add(new ArrayList<>());
		}
		
		for (int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine(), " ");
			int from = pint(st.nextToken())-1;
			int to = pint(st.nextToken())-1;
			
			adjList.get(from).add(to);
			adjList.get(to).add(from);
		}
		
		int count=-1;
		boolean findAns=false;
		boolean[] isVisit = new boolean[n];
		Queue<Integer> qu = new LinkedList<Integer>();
		qu.offer(a);
		while(!qu.isEmpty()) {
			count++;
			int len = qu.size();
			for (int i = 0; i < len; i++) {
				int cur = qu.poll();
				if(cur==b) {
					findAns=true;
					break;
				}
				
				for(int next : adjList.get(cur)) {
					if(!isVisit[next]) {
						isVisit[next]=true;
						qu.offer(next);
					}
				}
			}
			if(findAns)break;
		}
		
		System.out.println(findAns?count:-1);
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

1959번: 달팽이3

첫째 줄에 표의 모든 칸이 채워질 때까지 선이 꺾어지는 횟수를 출력한다. 둘째 줄에 끝나는 점의 좌표를 출력한다. 왼쪽 위 칸의 좌표를 (1, 1), 오른쪽 아래 칸의 좌표를 (M, N)이라고 하자.

www.acmicpc.net

 

0. 수학 문제

 

노랑 : 시작점 / 파랑 : 회전점 / 빨강 : 종료점

1. 위 그림과 같이n, m크기의 표에서 달팽이가 한바퀴를 이동하면, 총 4번 회전하고 시작점의 (+1, +1)위치에 서게되며, n-2, m-2크기의 표가 된다

 

2. 해당 과정을 n 혹은 m이 3보다 작아질때까지 반복한다

  • 즉, n과 m 둘 중 작은쪽이 1 혹은 2가 되는 횟수 x만큼 반복한다
  • 각 반복마다 4회 회전이 발생하므로, 이 시점까지 발생한 회전은 4x이다
  • 또한 이 시점에서 좌표는 (x, x)이다

 

3. n 혹은 m이 1 혹은 2까지 작아졌다면, 총 6가지 경우의 수가 존재한다

  • 1 * 1
  • 1 * m
  • n * 1
  • 2 * 2
  • 2 * m (2*2와 회전횟수 / 도착지점은 동일하다)
  • n * 2

 

파랑 : 회전점 / 빨강 : 종료점

4. 각 경우마다, 다음과 같은 경로를 거쳐 최종 도착지점에 도달하게 된다

 

5. n과 m의 값을 통해 어떤 경우인지 판단하고, 해당하는 회전 횟수 / 도착지점을 적용한다

 

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());
		
		long min = (Math.min(n, m)-1)/2;
		
		long x=min+1,y=min+1;
		long count = 4*min;
		
		n-=2*min;
		m-=2*min;
		if(n==1) {
			y+=m-1;
		}
		else if(m==1) {
			count++;
			x+=n-1;
			
		}
		else if(n==2) {
			count+=2;
			x++;
		}
		else {
			count+=3;
			x++;
		}
		System.out.println(count);
		System.out.println(x+" "+y);
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

16973번: 직사각형 탈출

크기가 N×M인 격자판에 크기가 H×W인 직사각형이 놓여 있다. 격자판은 크기가 1×1인 칸으로 나누어져 있다. 격자판의 가장 왼쪽 위 칸은 (1, 1), 가장 오른쪽 아래 칸은 (N, M)이다. 직사각형의 가장

www.acmicpc.net

 

0. 최단 거리 탐색 문제, BFS

 

1. 큰 덩어리가 움직이므로, 4방향 각각 이동 가능한지 판단하는 함수 chk를 만든다

 

2. 맵 크기가 1000*1000이므로 초기값은 1000000보다 큰 임의의 수를 선택

 

3. 시작지점부터 BFS로 탐색 진행

 

4. 최종 지점의 값이 초기값이라면 도달 불가하므로 -1을 출력, 값이 변했다면 해당 값을 출력한다

 

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{
	static int[][] map;
	static int[][] answer;
	static int H,W,Sx,Sy,Ex,Ey;
	static int ans;
	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());
		map = new int[n][m];
		answer = new int[n][m];
		
		for (int i = 0; i < n; i++) {
			Arrays.fill(answer[i], 1000001);
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < m; j++) {
				map[i][j] = pint(st.nextToken());
			}
		}
		st = new StringTokenizer(br.readLine());
		H = pint(st.nextToken()); W = pint(st.nextToken());
		Sx = pint(st.nextToken())-1; Sy = pint(st.nextToken())-1;
		Ex = pint(st.nextToken())-1; Ey = pint(st.nextToken())-1;
		
		Queue<int[]> qu = new LinkedList<int[]>();
		qu.offer(new int[] {Sx,Sy,0});
		answer[Sx][Sy]=0;
		//bfs
		while(!qu.isEmpty()) {
			int[] cur = qu.poll();
			if(cur[0]+H < n && answer[cur[0]+1][cur[1]]>cur[2]+1 && chk(cur[0], cur[1], 0) ) {
				answer[cur[0]+1][cur[1]]=cur[2]+1;
				qu.offer(new int[] {cur[0]+1, cur[1], cur[2]+1});
			}
			if(cur[0]-1 >=0 && answer[cur[0]-1][cur[1]]>cur[2]+1 && chk(cur[0], cur[1], 1) ) {
				answer[cur[0]-1][cur[1]]=cur[2]+1;
				qu.offer(new int[] {cur[0]-1, cur[1], cur[2]+1});
			}
			if(cur[1]-1 >=0 && answer[cur[0]][cur[1]-1]>cur[2]+1 && chk(cur[0], cur[1], 2) ) {
				answer[cur[0]][cur[1]-1]=cur[2]+1;
				qu.offer(new int[] {cur[0], cur[1]-1, cur[2]+1});
			}
			if(cur[1]+W < m && answer[cur[0]][cur[1]+1]>cur[2]+1 && chk(cur[0], cur[1], 3) ) {
				answer[cur[0]][cur[1]+1]=cur[2]+1;
				qu.offer(new int[] {cur[0], cur[1]+1, cur[2]+1});
			}
		}
		System.out.println(answer[Ex][Ey]>1000000 ? -1 : answer[Ex][Ey]);
	}

	static boolean chk(int x, int y, int type) {
		boolean returnV = true;
		if(type==0) {
			//chk down
			for (int i = y; i < y+W; i++) {
				if(map[x+H][i]==1)returnV=false;
			}
		}
		else if(type==1){
			//chk up
			for (int i = y; i < y+W; i++) {
				if(map[x-1][i]==1)returnV=false;
			}
		}
		else if(type==2){
			//chk left
			for (int i = x; i < x+H; i++) {
				if(map[i][y-1]==1)returnV=false;
			}
		}
		else if(type==3){
			//chk right
			for (int i = x; i < x+H; i++) {
				if(map[i][y+W]==1)returnV=false;
			}
		}return returnV;
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

23288번: 주사위 굴리기 2

크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 가장 왼

www.acmicpc.net

 

0. 구현 / 그래프 탐색 문제

 

1. 각 지점의 값 * 같은 값으로 연결된 지점의 수 = 해당 지점의 점수 이므로, 사전에 DFS를 진행해 scoreMap을 제작한다

 

2. dice의 방향은 동-남-서-북 순서로 정의, 2칸 차이나면 반대 방향이고, +1로 진행시 시계방향, -1로 진행시 반시계방향

 

3. 문제 정의대로 dice를 움직인다

  • 이동 가능 판단, 불가시 방향 반대로 전환
  • 해당 방향으로 1칸 이동 (roll 함수 이용), 점수 누적
  • map의 값과 dice값 비교를 통해 방향 전

 

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

public class Main{
	static int[] dice;
	static int[][] dir = {
			{0,1},{1,0},{0,-1},{-1,0}//시계방향 동남서북
	};
	static int[][]scoreMap;
	static int[][]map;
	
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		dice = new int[] {1, 3, 6, 4, 2, 5};//앞 오 바닥 왼 위 아래
		int x=0,y=0;//init pos 0,0
		int curDir=0;//east
		
		
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		int n = pint(st.nextToken());
		int m = pint(st.nextToken());
		int k = pint(st.nextToken());
		
		map = new int[n][m];
		scoreMap = new int[n][m];
		List<Integer> list = new ArrayList<>();
		
		for (int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine(), " ");
			for (int j = 0; j < m; j++) {
				map[i][j]=pint(st.nextToken());
			}
		}
		
		//1. scoremap에 연속된 갯수 구하기
		int cnt=1;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if(scoreMap[i][j]==0) {
					int curV=dfs(i,j,cnt++);
					list.add(curV);
				}
			}
		}
		//2. map의 값으로 곱, 최종 칸 당 점수 구하기
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				scoreMap[i][j] = list.get(scoreMap[i][j]-1);
				scoreMap[i][j] *=map[i][j];
			}
		}
		
		//3. 주사위 go
		int scoreSum=0;
		for (int i = 0; i < k; i++) {
			//한칸 굴러간다
			int nextX = x+dir[curDir][0];
			int nextY = y+dir[curDir][1];
			//못가면 반대로 굴러간다
			if(nextX<0 || nextX>=n || nextY<0 || nextY>=m) {
				curDir = (curDir+2)%4;
				nextX = x+dir[curDir][0];
				nextY = y+dir[curDir][1];
			}
			x=nextX;y=nextY;
			//해당 방향으로 구르기
			roll(curDir);
			
			//점수먹기
			scoreSum += scoreMap[x][y];
			//방향바꾸기
			//바닥면 = dice[2]
			if(map[x][y]<dice[2]) {
				//밑면이 더 크면 시계방향
				curDir= (curDir+1)%4;
			}
			else if(map[x][y]>dice[2]) {
				//밑면이 더 작으면 반시계방향
				curDir= (curDir+4-1)%4;
			}
			else {
				//do nothing
			}
		}
		System.out.println(scoreSum);
	}
	static void roll(int curDir) {
		int tmp;
		//앞 오 바닥 왼 위 아래
		//east
		if(curDir==0) {
			roll(2);
			roll(2);
			roll(2);
		}
		//south
		else if(curDir==1) {
			tmp = dice[0];
			dice[0]=dice[4];
			dice[4]=dice[2];
			dice[2]=dice[5];
			dice[5]=tmp;
		}
		//west
		else if(curDir==2) {
			tmp = dice[0];
			dice[0]=dice[1];
			dice[1]=dice[2];
			dice[2]=dice[3];
			dice[3]=tmp;
		}
		//north
		else if(curDir==3) {
			roll(1);
			roll(1);
			roll(1);
		}
		
	}
	static int dfs(int x, int y, int cur) {
		int num=1;
		scoreMap[x][y]=cur;
		
		if(x-1>=0 && map[x-1][y]==map[x][y] && scoreMap[x-1][y]==0) {
			num+=dfs(x-1,y,cur);
		}
		if(x+1<map.length && map[x+1][y]==map[x][y] && scoreMap[x+1][y]==0) {
			num+=dfs(x+1,y,cur);
		}
		if(y-1>=0 && map[x][y-1]==map[x][y] && scoreMap[x][y-1]==0) {
			num+=dfs(x,y-1,cur);
		}
		if(y+1<map[0].length && map[x][y+1]==map[x][y] && scoreMap[x][y+1]==0) {
			num+=dfs(x,y+1,cur);
		}
		
		return num;
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

19236번: 청소년 상어

첫째 줄부터 4개의 줄에 각 칸의 들어있는 물고기의 정보가 1번 행부터 순서대로 주어진다. 물고기의 정보는 두 정수 ai, bi로 이루어져 있고, ai는 물고기의 번호, bi는 방향을 의미한다. 방향 bi는

www.acmicpc.net

 

0. 백트래킹 / 구현 문제

 

1. 백트래킹을 위하여, 상어의 각 이동 단계마다 map과 물고기 방향 정보를 저장한다

 

2. 해당 상황에서 물고기 이동 - 가능한 모든 상어 이동에 대해 재귀를 돌린 다음, 저장해둔 정보를 복원하고 이전 단계로 돌아간다

 

3. 각 재귀 단계에서 먹은 물고기 번호의 합을 저장, 더이상 진행 불가능할때 전역변수인 maxEat과 비교, 갱신한다

 

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

public class Main{
	static int[][] dir = {
			{-1,0},{-1,-1},{0,-1},{1,-1},
			{1,0},{1,1},{0,1},{-1,1}
	};
	static int maxEat=0;
	static boolean[] deadFish;
	static int[][] fish;
	static int[][] map;
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		map = new int[4][4];
		fish = new int[17][3];
		deadFish = new boolean[17];
		for (int i = 0; i < 4; i++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			for (int j = 0; j < 4; j++) {
			
				int num = pint(st.nextToken());
				int dir = pint(st.nextToken());
				map[i][j]=num;
				fish[num][0]=i;
				fish[num][1]=j;
				fish[num][2]=dir-1;
			}
		}
		//fish[0] = shark
		deadFish[map[0][0]]=true;
		maxEat+=map[0][0];
		fish[0][2] = fish[ map[0][0] ][2];
		map[0][0]=-1;
		
		rec(maxEat);
		System.out.println(maxEat);
	}
	
	static void rec(int eat) {
		//comparemaxEat
		if(maxEat<eat)maxEat=eat;
		
		
		int[][]tmpMap = new int[4][4];
		int[][] tmpFish = new int[17][3];
		boolean[] tmpDeadFish = new boolean[17];
		//backup
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				tmpMap[i][j]=map[i][j];
			}
		}
		for (int i = 0; i < 17; i++) {
			tmpFish[i][0]=fish[i][0];
			tmpFish[i][1]=fish[i][1];
			tmpFish[i][2]=fish[i][2];
			tmpDeadFish[i]=deadFish[i];
		}

		//fish move
		for (int i = 1; i < 17; i++) {
			if(deadFish[i])continue;//죽었다면 넘어감
			
			int curX = fish[i][0], curY = fish[i][1], curDir = fish[i][2];
			for (int j = 0; j < 8; j++) {
				//ok?
				int nX = curX+dir[curDir][0];
				int nY = curY+dir[curDir][1];
				if(nX<0 || nY<0 || nX>=4 || nY>=4 || map[nX][nY]==-1) {
					curDir= (curDir+1)%8; continue;
				}
				
				//swap
				int tmp = map[nX][nY];
				map[nX][nY]=map[curX][curY];
				map[curX][curY]=tmp;
				
				fish[i][0]=nX;fish[i][1]=nY;
				fish[i][2]=curDir;

				if(tmp!=0) {
					fish[tmp][0]=curX;
					fish[tmp][1]=curY;
				}
				
				break;
			}
		}
		
		//shark move
		//eat
		map[ fish[0][0] ][ fish[0][1] ]=0;//빈 공간화
		while(true) {
			fish[0][0]+=dir[fish[0][2]][0];
			fish[0][1]+=dir[fish[0][2]][1];
			
			if(fish[0][0]<0 || fish[0][0]>=4 || fish[0][1]<0 || fish[0][1]>=4) {
				break;
			}
			if(map[fish[0][0]][fish[0][1]]==0)continue;
			
			int tmp = map[ fish[0][0] ][ fish[0][1] ];
			
			map[ fish[0][0] ][ fish[0][1] ]=-1;
			deadFish[tmp]=true;
			int tmpShakeDir = fish[0][2];
			fish[0][2]=fish[tmp][2];
			
			rec(eat+tmp);
			
			fish[0][2]=tmpShakeDir;
			map[ fish[0][0] ][ fish[0][1] ]=tmp;
			deadFish[tmp]=false;
		}
		
		//return
		//restore
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				map[i][j]=tmpMap[i][j];
			}
		}
		for (int i = 0; i < 17; i++) {
			fish[i][0]=tmpFish[i][0];
			fish[i][1]=tmpFish[i][1];
			fish[i][2]=tmpFish[i][2];
			deadFish[i]=tmpDeadFish[i];
		}
		return;
	}
	
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

2346번: 풍선 터뜨리기

1번부터 N번까지 N개의 풍선이 원형으로 놓여 있고. i번 풍선의 오른쪽에는 i+1번 풍선이 있고, 왼쪽에는 i-1번 풍선이 있다. 단, 1번 풍선의 왼쪽에 N번 풍선이 있고, N번 풍선의 오른쪽에 1번 풍선

www.acmicpc.net

 

1. 사용한 풍선은 표시해두고, 지나가더라도 카운트하지 않는다

 

2. 양 끝 간 이동 처리를 위해, 증감시 N으로 나머지 연산

 

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));
		StringBuilder sb = new StringBuilder();
		
		int N = pint(br.readLine());
		int[] num = new int[N];
		boolean[] chk = new boolean[N];
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		for (int i = 0; i < N; i++) {
			num[i]=pint(st.nextToken());
		}
		
		int cur=0;
		sb.append(cur+1).append(" ");
		int move = num[cur];
		chk[cur]=true;
		for (int i = 1; i < N; i++) {
			int cnt=0;
			while(cnt<Math.abs(move)) {
				if(move>0) {
					cur++;
					cur%=N;
					if(chk[cur])continue;
				}
				else {
					cur--;
					cur+=N;
					cur%=N;
					if(chk[cur])continue;
				}
				cnt++;
			}
			sb.append(cur+1).append(" ");
			move = num[cur];
			chk[cur]=true;
		}System.out.println(sb);
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

20058번: 마법사 상어와 파이어스톰

마법사 상어는 파이어볼과 토네이도를 조합해 파이어스톰을 시전할 수 있다. 오늘은 파이어스톰을 크기가 2N × 2N인 격자로 나누어진 얼음판에서 연습하려고 한다. 위치 (r, c)는 격자의 r행 c

www.acmicpc.net

 

0. 단순 구현 + 그래프 탐색 문제

 

1. 주어진 l 값에 맞게, 각 칸을 회전시킨다

 

2. 다른 얼음과 2칸 이하로 맞닿은 칸들을 체크한다

 

3. 해당 칸들을 녹인다

 

4. 1~3 반복

 

5. 다 녹은 후 dfs를 실행, 가장 큰 덩어리의 크기를 찾는다

 

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

public class Main{
	static int[][]map;
	static boolean[][] chk;
	static int size;
	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());
		size = 1<<n;
		map = new int[size][size];
		for (int i = 0; i < size; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < size; j++) {
				map[i][j]=pint(st.nextToken());
			}
		}
		
		st = new StringTokenizer(br.readLine());
		for (int i = 0; i < m; i++) {
			int l = pint(st.nextToken());
			chk=new boolean[size][size];
			//돌리기
			divide(l);
			//녹일것찾기
			findMelt();
			//녹이기
			melt();
		}

		//dfs search
		chk=new boolean[size][size];
		int cntMax=0;
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				if(!chk[i][j] && map[i][j]>0) {
					cntMax = Math.max(cntMax, dfs(i,j));
				}
			}
		}
		
		int sum=0;
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				sum+=map[i][j];
			}
		}
		System.out.println(sum+"\n"+cntMax);
		
	}
	
	static int dfs(int x, int y) {
		int cnt=1;
		chk[x][y]=true;
		if(x>0 && !chk[x-1][y] && map[x-1][y]>0)cnt+=dfs(x-1,y);
		if(y>0 && !chk[x][y-1] && map[x][y-1]>0)cnt+=dfs(x,y-1);
		if(x<size-1 && !chk[x+1][y] && map[x+1][y]>0)cnt+=dfs(x+1,y);
		if(y<size-1 && !chk[x][y+1] && map[x][y+1]>0)cnt+=dfs(x,y+1);
		
		return cnt;
	}
	
	static void divide(int l) {
		int len = size / (1<<l);
		for (int i = 0; i < len; i++) {
			for (int j = 0; j < len; j++) {
				rotate(i*(1<<l), j*(1<<l), 1<<l);
			}
		}
	}
	
	static void findMelt() {
		for (int x = 0; x < size; x++) {
			for (int y = 0; y < size; y++) {
				int cnt=0;
				if(x>0 && map[x-1][y]>0)cnt++;
				if(y>0 && map[x][y-1]>0)cnt++;
				if(x<size-1 && map[x+1][y]>0)cnt++;
				if(y<size-1 && map[x][y+1]>0)cnt++;
				
				if(cnt<3 && map[x][y]>0) {
					chk[x][y]=true;
				}
			}
		}
	}
	static void melt() {
		for (int x = 0; x < size; x++) {
			for (int y = 0; y < size; y++) {
				if(chk[x][y])map[x][y]--;
			}
		}
	}
	
	static void rotate(int sx, int sy, int len) {
		if(len<=0)return;
		
		int tmp=len-1;
		int[] backup = new int[tmp];
		
		for (int i = 0; i < tmp; i++)backup[i]=map[sx][sy+i];
		
		for (int i = 0; i < tmp; i++) {
			map[sx][sy+tmp-1-i]=map[sx+i+1][sy];
		}
		for (int i = 0; i < tmp; i++) {
			map[sx+i+1][sy]=map[sx+tmp][sy+i+1];		
		}
		for (int i = 0; i < tmp; i++) {
			map[sx+tmp][sy+i+1]=map[sx+tmp-1-i][sy+tmp];
		}
		for (int i = 0; i < tmp; i++) {
			map[sx+tmp-1-i][sy+tmp]=backup[tmp-1-i];
		}
		rotate(sx+1,sy+1,len-2);
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

21610번: 마법사 상어와 비바라기

마법사 상어는 파이어볼, 토네이도, 파이어스톰, 물복사버그 마법을 할 수 있다. 오늘 새로 배운 마법은 비바라기이다. 비바라기를 시전하면 하늘에 비구름을 만들 수 있다. 오늘은 비바라기

www.acmicpc.net

 

0. 단순 구현 문제

 

1. 구름을 이동하고 -> 대각선 물 양을 증가시키고 -> 새 구름을 생성한다 의 반복

 

2. 구름이 사라진 칸은 boolean 배열로 관리한다

 

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[][] dir = new int[][]{
		{0,-1},{-1,-1},{-1,0},{-1,1},
		{0,1},{1,1},{1,0},{1,-1}
	};
	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 sum=0;
		
		int[][]map = new int[n][n];
		boolean[][]chk;
		
		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());
			}
		}
		
		Queue<int[]> cloud = new LinkedList<>();
		cloud.add(new int[] {n-1,0}); cloud.add(new int[] {n-1,1});
		cloud.add(new int[] {n-2,0}); cloud.add(new int[] {n-2,1});
		
		for (int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int d = pint(st.nextToken())-1;
			int s = pint(st.nextToken());
			chk=new boolean[n][n];
			//구름 이동 페이즈
			int len = cloud.size();
			for (int j = 0; j < len; j++) {
				int[] cur = cloud.poll();
				int newX = cur[0]+dir[d][0]*s;
				int newY = cur[1]+dir[d][1]*s;
				newX = ((newX%n)+n)%n;
				newY = ((newY%n)+n)%n;
				//1증가
				map[newX][newY]++;
				cloud.add(new int[] {newX,newY});
			}
			
			//이동 후 물양 증가 페이즈
			for (int j = 0; j < len; j++) {
				int[] cur = cloud.poll();
				if(cur[0]-1>=0 && cur[1]-1>=0 && map[cur[0]-1][cur[1]-1]>0) {
					map[cur[0]][cur[1]]++;
				}if(cur[0]-1>=0 && cur[1]+1<n && map[cur[0]-1][cur[1]+1]>0) {
					map[cur[0]][cur[1]]++;
				}if(cur[0]+1<n && cur[1]-1>=0 && map[cur[0]+1][cur[1]-1]>0) {
					map[cur[0]][cur[1]]++;
				}if(cur[0]+1<n && cur[1]+1<n && map[cur[0]+1][cur[1]+1]>0) {
					map[cur[0]][cur[1]]++;
				}
				chk[cur[0]][cur[1]]=true;
			}
			
			//신규 구름 생성 페이즈
			
			for (int j = 0; j < n; j++) {
				for (int j2 = 0; j2 < n; j2++) {
					if(!chk[j][j2] && map[j][j2]>=2) {
						map[j][j2]-=2;
						cloud.add(new int[] {j,j2});
					}
				}
			}
		}
		for (int x = 0; x < n; x++) {
			for (int y = 0; y < n; y++) {
				sum+=map[x][y];
			}
		}System.out.println(sum);
		
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

 

+ Recent posts