[문제링크]

 

2631번: 줄세우기

KOI 어린이집에는 N명의 아이들이 있다. 오늘은 소풍을 가는 날이다. 선생님은 1번부터 N번까지 번호가 적혀있는 번호표를 아이들의 가슴에 붙여주었다. 선생님은 아이들을 효과적으로 보호하기

www.acmicpc.net

 

0. 아이의 위치를 최소한으로 바꾸면서 순서를 정렬하는 방법 = 이미 정렬된 가장 긴 문자열을 찾고, 그 나머지를 이동하면 된다

  • 가장 긴 증가하는 부분 수열(LIS)을 구하면 된다

 

1. DP를 통해 이전까지 진행한 결과들 중 현재 순서보다 작으면서 그 값이 제일 큰 값을 구한다

 

2. 해당 값 +1이 현재 지점까지의 LIS이다

 

3. LIS를 마지막까지 구한 후, 가장 큰 LIS 길이를 구한다

 

4. 해당 LIS에 속하지 않는 아이들을 이동하면 된다. 즉, (전체 아이 수 - LIS길이) = (이동해야하는 아이 수)

 

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 = pint(br.readLine());
		int[] num = new int[N];
		int[] dp = new int[N];
		for (int i = 0; i < N; i++) {
			num[i]=pint(br.readLine());
		}
		int lis=0;
		for (int i = 0; i < N; i++) {
			int max=0;
			for (int j = 0; j < i; j++) {
				if(num[j] < num[i]  && max<dp[j])max=dp[j];
			}
			dp[i]=max+1;
			lis = Math.max(dp[i], lis);
		}
		System.out.println(N-lis);
	}
	
	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);
	}
}

결과 화면

[문제링크]

 

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);
	}
}

결과 화면

 

[문제링크]

 

1339번: 단어 수학

첫째 줄에 단어의 개수 N(1 ≤ N ≤ 10)이 주어진다. 둘째 줄부터 N개의 줄에 단어가 한 줄에 하나씩 주어진다. 단어는 알파벳 대문자로만 이루어져있다. 모든 단어에 포함되어 있는 알파벳은 최대

www.acmicpc.net

 

0. 각 알파벳의 총 크기를 구해, 그리디하게 숫자를 부여한다

  • ex) AB, BC의 경우, A는 10의자리에 1번 나오니 10, B는 11, C는 1
  • B가 가장 크므로 9, 그다음인 A에 8, C에 7을 주는 식

 

1. 모든 수에 대해 알파벳별로 등장 자릿수에 따라 값을 누적시킨다

 

2. 종료시 내림차순 정렬, 값이 큰 순으로 9~0까지 값을 부여하며 진행한다

  • 알파벳이 10개 이하로 존재하여도, tmp배열의 초깃값이 0이므로 문제 없음

 

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

public class Main{
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		Integer[] tmp = new Integer[26];
		int N = pint(br.readLine());
		int num=9, sum=0;
		for (int i=0; i<26; i++)tmp[i]=0;
		for (int i = 0; i < N; i++) {
			String s = br.readLine();
			for (int j = 0; j < s.length(); j++)tmp[s.charAt(j)-'A']+= (int)Math.pow(10, s.length()-j-1);		
		}
		Arrays.sort(tmp, Comparator.reverseOrder());
		for (int i = 0; i < 10; i++)sum+=tmp[i]*num--;
		System.out.println(sum);
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

+ Recent posts