[문제링크]

 

17276번: 배열 돌리기

각 테스트 케이스에 대해 회전 연산을 마친 후 배열의 상태를 출력한다. n줄에 걸쳐 각 줄에 n개의 정수를 공백으로 구분하여 출력한다. 

www.acmicpc.net

 

0. 단순한 구현 문제

 

1. 4개의 대각선을 옮기는 작업을 한다

  • 두 수를 swap하듯, 하나를 백업하고 후에 복구

 

2. -X 각도로의 회전은 360-X 각도의 회전과 같다

  • 별도의 함수를 만들지 않고, 45도 회전 함수를 동일하게 사용

 

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

public class Main{
	static int[][] map;
	static int n,d;
	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 test = 1; test <= tc; test++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			n = pint(st.nextToken());
			d = pint(st.nextToken())/45;
			if(d<0)d+=8;
			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());
				}
			}
			
			for (int i = 0; i < d; i++) {
				spin();
			}
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < n; j++) {
					sb.append(map[i][j]).append(" ");
				}sb.append("\n");
			}
		}System.out.println(sb);
	}
	static void spin() {
		int[] backup = new int[n];
		for (int i = 0; i < n; i++)backup[i]=map[i][i];//백업
		
		for (int i = 0; i < n; i++)map[i][i]=map[n/2][i];
		for (int i = 0; i < n; i++)map[n/2][i]=map[n-i-1][i];
		for (int i = 0; i < n; i++)map[n-i-1][i]=map[n-i-1][n/2];
		for (int i = 0; i < n; i++)map[i][n/2]=backup[i];
	}
	
	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);
	}
}

결과 화면

[문제링크]

 

14938번: 서강그라운드

예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을

www.acmicpc.net

 

0. m 이하의 cost로 방문 가능한 노드가 가장 많은 노드 찾기

  • 다익스트라를 n번 돌리거나, 플로이드-와샬 진행

 

1. 편의를 위해, 갈 수 없는 노드는 큰 값(2000)으로 초기화한다

  • 최대 거리가 15, 노드가 100개이므로 두 노드의 거리는 15*99=1485가 최대값이다

 

2. 노드 간 거리 정보를 저장하고, 플로이드-와샬을 진행해 각 노드간 거리를 구한다

 

3. 각 노드 별 방문 가능한 노드들로부터 획득 아이템 갯수를 종합, 최댓값을 출력한다

 

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 r = pint(st.nextToken());
		
		int[][]map=new int[n][n];
		for (int i = 0; i < n; i++) {
			Arrays.fill(map[i], 2000);
		}
		int[] item=new int[n];
		
		st = new StringTokenizer(br.readLine());
		for (int i = 0; i < n; i++) {
			item[i]=pint(st.nextToken());
		}
		
		for (int i = 0; i < r; i++) {
			st = new StringTokenizer(br.readLine());
			int n1 = pint(st.nextToken())-1;
			int n2 = pint(st.nextToken())-1;
			int c = pint(st.nextToken());
			
			map[n1][n2]=c;
			map[n2][n1]=c;
		}

		for (int k = 0; k < n; k++) {
			for (int i = 0; i < n; i++) {
				if(i==k)continue;
				for (int j = 0; j < n; j++) {
					if(i==j)continue;
					map[i][j]=Math.min(map[i][j],map[i][k]+map[k][j]);
				}
			}
		}
		
		int max_item=0;
		for (int i = 0; i < n; i++) {
			map[i][i]=0;
			int temp=0;
			for (int j = 0; j < n; j++) {
				if(map[i][j]<=m) {
					temp+=item[j];
				}
			}
			max_item=Math.max(temp, max_item);
		}
		System.out.println(max_item);
		
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

14891번: 톱니바퀴

총 8개의 톱니를 가지고 있는 톱니바퀴 4개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴

www.acmicpc.net

 

0. 구현문제. 요구사항을 잘 구현한다

 

1. 톱니바퀴의 연쇄 회전 : 회전 여부를 저장하는 boolean 배열과 재귀로 진행

 

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

public class Main{
	static boolean[][] wheel;
	static boolean[] isTurn;
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		
		//s극 : true, n극 : false
		wheel = new boolean[4][8];
		
		for (int i = 0; i < 4; i++) {
			String s = br.readLine();
			for (int j = 0; j < 8; j++) {
				wheel[i][j]=s.charAt(j)-'0'==1?true:false;
			}
		}
		
		int n = pint(br.readLine());
		for (int i = 0; i < n; i++) {
			st = new StringTokenizer(br.readLine(), " ");
			
			int num = pint(st.nextToken())-1;
			int dir = pint(st.nextToken());

			isTurn=new boolean[4];
			turn(num,dir);//1:시계, -1:반시계
		}
		int score=0;
		for (int i = 0; i < 4; i++) {
			if(wheel[i][0])score+=1<<i;
		}
		System.out.println(score);
		
	}
	
	static void turn(int n, int dir) {
		isTurn[n]=true;
		if(n<3 && !isTurn[n+1] && wheel[n][2]!=wheel[n+1][6])turn(n+1, dir==1?-1:1);
		if(n>0 && !isTurn[n-1] && wheel[n][6]!=wheel[n-1][2])turn(n-1, dir==1?-1:1);
		
		if(dir==1) {
			boolean tmp = wheel[n][7];
			for (int i = 7; i > 0; i--) {
				wheel[n][i] = wheel[n][i-1];
			}wheel[n][0]=tmp;
		}
		else {
			boolean tmp = wheel[n][0];
			for (int i = 0; i < 7; i++) {
				wheel[n][i] = wheel[n][i+1];
			}wheel[n][7]=tmp;
		}
	}
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

16919번: 봄버맨 2

첫째 줄에 R, C, N (1 ≤ R, C ≤ 200, 1 ≤ N ≤ 109)이 주어진다. 둘째 줄부터 R개의 줄에 격자판의 초기 상태가 주어진다. 빈 칸은 '.'로, 폭탄은 'O'로 주어진다.

www.acmicpc.net

 

0. 같은 코드로 봄버맨1(링크)도 해결 가능하다

 

1. 시작 직후를 제외하면, 빈공간을 채운다 - 터진다 - 빈공간을 채운다 - 터진다 - ... 순으로 반복되게 된다

 

2. 특정 시점 x에 폭탄이 놓인다면, x+1시점에는 x-2때 설치된 폭탄들이 터지며 방금 놓인 폭탄 중 일부가 제거된다

  • 이때 제거된 폭탄들은, x시점에 놓인 폭탄들 중 외곽과 닿은 폭탄들이다

 

3. x+2시점에는 새 폭탄이 설치되고, x+3시점에는 x때 설치된 폭탄들이 터지며 x+2폭탄 중 일부가 제거된다

  • 이때 제거된 폭탄들은, x시점에 놓인 폭탄들과 닿은 폭탄들이다

 

4.  즉, 2번에서 제거된 폭탄들과 3번에서 제거된 폭탄들은 그 위치가 같다

  • 얼음의 겉이 1칸 녹은 후, 다시 겉을 얼린다면 처음 그대로의 상태일 것
  • 항상 같은 위치를 제거해가며, 4초를 주기로 무한루프하게 된다

 

5. 즉 시작 직후만 따로 처리해주고, 나머지는 4로 나눈 만큼 진행하면 된다

  • 이때, 폭탄이 설치되는 짝수 시간에는 모든 칸에 폭탄이 위치하므로 진행할 필요 없이 처리 가능하다

 

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

public class Main{
	
	static int[][]map;
	static final int empty=-1;
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		
		
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		int r = pint(st.nextToken());
		int c = pint(st.nextToken());
		int n = pint(st.nextToken());
		map = new int[r][c];

		for (int i = 0; i < r; i++) {
			String s = br.readLine();
			for (int j = 0; j < c; j++) {
				map[i][j]=s.charAt(j)=='.'?empty:0;
			}
		}
		
		if(n==1) {
			for (int i = 0; i < r; i++) {
				for (int j = 0; j < c; j++) {
					sb.append(map[i][j]==empty?'.':'O');
				}sb.append("\n");
			}
		}
		else if(n%2==0) {
			for (int i = 0; i < r; i++) {
				for (int j = 0; j < c; j++) {
					sb.append("O");
				}sb.append("\n");
			}
		}
		else {
			n=n%4+4;
			for(int i = 2; i <= n; i++) {
				if(i%2==0) {
					set(true, i);
				}
				else {
					set(false,i);
				}
			}

			for (int i = 0; i < r; i++) {
				for (int j = 0; j < c; j++) {
					sb.append(map[i][j]==empty?'.':'O');
				}sb.append("\n");
			}
		}
		
		System.out.println(sb);
	}
	
	static void set(boolean mode, int time) {
		if(mode) {//set
			for (int i = 0; i < map.length; i++) {
				for (int j = 0; j < map[0].length; j++) {
					if(map[i][j]==empty)map[i][j]=time;
				}
			}
		}
		else {
			for (int i = 0; i < map.length; i++) {
				for (int j = 0; j < map[0].length; j++) {
					if(map[i][j]==time-3)bomb(i,j,time-3);
				}
			}
		}
	}
	static void bomb(int x, int y, int time) {
		map[x][y]=empty;
		if(y<map[0].length-1 && map[x][y+1]!=time)map[x][y+1]=empty;
		if(y>0 && map[x][y-1]!=time)map[x][y-1]=empty;
		if(x < map.length-1 && map[x+1][y]!=time)map[x+1][y]=empty;
		if(x>0 &&map[x-1][y]!=time)map[x-1][y]=empty;
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

4256번: 트리

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스의 첫째 줄에는 노드의 개수 n이 주어진다. (1 ≤ n ≤ 1,000) BT의 모든 노드에는 1부터 n까지 서로 다른 번호가 매겨져 있다. 다음

www.acmicpc.net

 

1. 현재 노드 x를 기준으로, 전위 순회는 x-[왼쪽]-[오른쪽] 의 순서로, 중위 순회는 [왼쪽]-x-[오른쪽]의 순서로 만들어진다

 

2. 즉, 전위 순회 결과의 첫 노드를 기준으로, 중위 순회의 왼쪽과 오른쪽을 분리할 수 있다.

 

3. 또한 왼쪽과 오른쪽 subtree에 대해서도 동일한 작업으로 분리할 수 있다.

  • 최종적으로 tree의 크기가 1이 되면, leaf 노드가 된다

 

4. tree를 입력받아, root 노드를 만들어 반환하는 함수를 만들 수 있다.

  • 두 자식 노드는 동일 함수에 left/right subtree에 대해 재귀 돌려 구할 수 있다.

 

5. 이때 재귀 순서를 왼쪽->오른쪽으로 진행하면, 전위 순회와 진행 순서가 일치하게 된다

  • 즉, 매 재귀 단계마다 전위순회의 다음번 노드가 곧 root노드가 된다 (전역변수로 관리)
  • 중위 순회의 left/right만 관리하면 된다

 

6. 복원한 원형 tree로부터 후위 순회 결과를 얻어낸다

 

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

public class Main{
	
	static class node{
		int num;
		node left;
		node right;
		node(int num){
			this.num=num;
		}
	}
	static int cnt;
	static int[] pre;
	static int[] in;
	static StringBuilder sb;
	public static void main(String[] args)throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int tc = pint(br.readLine());
		for (int test = 1; test <= tc; test++) {
			int n = pint(br.readLine());
			pre = new int[n];
			in = new int[n];
			cnt=0;
			StringTokenizer st = new StringTokenizer(br.readLine(), " ");
			StringTokenizer st2 = new StringTokenizer(br.readLine(), " ");
			for (int j = 0; j < n; j++) {
				pre[j]=pint(st.nextToken());
				in[j]=pint(st2.nextToken());
			}
			
			node head = restore(0, n); //restore original tree
			
			sb = new StringBuilder();
			postorder(head);
			System.out.println(sb);
		}
	}
	
	static node restore(int s, int e) {
		if(s==e)return null; //leaf node
		int cur = pre[cnt++]; //head of current subtree
		node n = new node(cur); //node
		for (int i = s; i < e; i++) {
			if(cur==in[i]) {
				n.left=restore(s, i); //left child
				n.right=restore(i+1, e); //right child
			}
		}
		
		return n;
	}
	
	static void postorder (node n) {
		if(n.left!=null)postorder(n.left);
		if(n.right!=null)postorder(n.right);
		sb.append(n.num).append(" ");
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

1325번: 효율적인 해킹

첫째 줄에, N과 M이 들어온다. N은 10,000보다 작거나 같은 자연수, M은 100,000보다 작거나 같은 자연수이다. 둘째 줄부터 M개의 줄에 신뢰하는 관계가 A B와 같은 형식으로 들어오며, "A가 B를 신뢰한

www.acmicpc.net

 

0. 방향 그래프에서, 가장 많은 노드를 방문할 수 있는 노드 찾기

 

1. 정점 N에 비해 간선 M의 범위가 작으므로, 그래프의 저장은 List로 한다

 

2. 모든 정점에 대해 BFS로 방문 가능한 노드 갯수를 탐색, 저장한다

 

3. 최댓값을 가지는 정점들을 출력한다

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
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));
		StringBuilder sb = new StringBuilder();
		
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		int n = pint(st.nextToken());
		int m = pint(st.nextToken());
		int[] result = new int[n];
		int max=0;
		List<List<Integer>> graph = new ArrayList<>();
		
		for (int i = 0; i < n; i++)graph.add(new ArrayList<>());
		
		for (int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine(), " ");
			int a = pint(st.nextToken())-1;
			int b = pint(st.nextToken())-1;
			graph.get(b).add(a);
		}
		
		for (int i = 0; i < n; i++) {
			//각각 서치 돌려보고, 결과값 추리기
			int cnt=0;
			
			Queue<Integer>qu = new LinkedList<Integer>();
			qu.offer(i);
			boolean[] isV=new boolean[n];
			isV[i]=true;
			while(!qu.isEmpty()) {
				int cur = qu.poll();
				cnt++;
				for (int next : graph.get(cur)) {
					if(!isV[next]) {
						isV[next]=true;
						qu.offer(next);
					}
				}
			}
			result[i]=cnt;
			if(max<cnt)max=cnt;
		}
		for(int i=0; i<n; i++) {
			if(result[i]==max)sb.append(i+1).append(" ");
		}sb.setLength(sb.length()-1);
		System.out.println(sb);
		
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

[문제링크]

 

20056번: 마법사 상어와 파이어볼

첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다. 서로 다른 두 파이어볼의 위치

www.acmicpc.net

 

0. 빠트린 부분 없이 잘 구현하면 되는 구현문제 (불가능)

 

1. 파이어볼 질량은 겹친 파이어볼이 분리될때에만 변경된다

  • 초기 질량합을 구해서 유지, 파이어볼 분리 작업마다 질량합을 수정한다

 

2. Fireball은 위치 + 질량/방향/속도 값을 가지며, 끊임없이 움직인다

  • 배열 : 여러 fireball을 저장하기 힘들다
  • List : fireball을 제거/이동하기 힘들다
  • Stack : push/pop으로 쉽게 이용 가능
  • 이런 이유로 Stack 사용

 

3. Stack을 가지는 class를 만들어 2차원 배열로 구현, Fireball의 위치 값을 표현했다

 

4. 이동 이후 Stack의 size가 1보다 크면 분리 작업 수행

 

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

public class Main{
	static class Fireball{
		Stack<int[]>balls;
		public Fireball() {
			balls= new Stack<>();
		}
	}
	static int[][] dir= new int[][] {
		{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-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 K = pint(st.nextToken());
		int totalW=0;
		
		Fireball[][] fireballs = new Fireball[N][N];
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				fireballs[i][j]=new Fireball();
			}
		}
		
		for (int i = 0; i < M; i++) {
			int w;
			st = new StringTokenizer(br.readLine(), " ");
			fireballs[pint(st.nextToken())-1][pint(st.nextToken())-1]
					.balls.add(new int[] {w=pint(st.nextToken()),pint(st.nextToken()),pint(st.nextToken())});
			totalW+=w;
		}
		
		for (int i = 0; i < K; i++) {
			List<int[]> l = new ArrayList<>();
			//이동 시작
			for (int j = 0; j < N; j++) {
				for (int j2 = 0; j2 < N; j2++) {
					while(!fireballs[j][j2].balls.isEmpty()) {
						int[] ball = fireballs[j][j2].balls.pop();
						int x = j + dir[ball[2]][0]*ball[1]+N;
						int y = j2+ dir[ball[2]][1]*ball[1]+N;
						x%=N; if(x<0)x+=N;
						y%=N; if(y<0)y+=N;
						l.add(new int[] {x,y,ball[0],ball[1],ball[2]});
					}
				}
			}
			for (int[] b : l) {
				fireballs[b[0]][b[1]].balls.add(new int[] {b[2],b[3],b[4]});
			}
			
			//이동 끝
			for (int j = 0; j < N; j++) {
				for (int j2 = 0; j2 < N; j2++) {
					int size=0;
					if( (size = fireballs[j][j2].balls.size()) >1) {
						boolean same = true;
						int[] ball=fireballs[j][j2].balls.pop();
						int ballW = ball[0];//m,s,d
						int ballS = ball[1];
						int fstDir = ball[2]%2;
						int newDir=0;
						
						for (int o = 1; o < size; o++) {
							ball=fireballs[j][j2].balls.pop();
							ballW += ball[0];//m,s,d
							ballS += ball[1];
							if(fstDir != ball[2]%2)same=false;
						}
						totalW-=ballW;
						ballW/=5;
						ballS/=size;
						totalW+=ballW*4;
						
						if(ballW==0)continue;//0이면 소멸
						if(!same)newDir=1;
						for (int o = 0; o < 4; o++) {
							fireballs[j][j2].balls.add(new int[] {ballW, ballS, newDir});
							newDir+=2;
						}
					}
				}
			}//겹친 파이어볼 분리 끝
			
		}//K번 실행 끝
		System.out.println(totalW);
	}
	
	static int pint(String s) {
		return Integer.parseInt(s);
	}
}

결과 화면

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

[백준] 14891 - 톱니바퀴  (0) 2021.09.27
[백준] 16919 - 봄버맨 2  (0) 2021.09.25
[백준] 4256 - 트리  (0) 2021.09.25
[백준] 6198 - 옥상 정원 꾸미기  (0) 2021.08.27
[백준] 2075 - N번째 큰 수  (0) 2021.08.27
[백준] 3190 - 뱀  (0) 2021.08.08
[백준] 14719 - 빗물  (0) 2021.08.08

+ Recent posts