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

 

23290번: 마법사 상어와 복제

첫째 줄에 물고기의 수 M, 상어가 마법을 연습한 횟수 S가 주어진다. 둘째 줄부터 M개의 줄에는 물고기의 정보 fx, fy, d가 주어진다. (fx, fy)는 물고기의 위치를 의미하고, d는 방향을 의미한다. 방향

www.acmicpc.net

 

골드1 문제를 1트라이 만에 푼게 너무 뿌듯해서 공유한다..

시뮬레이션 문제이다.

 

package baekjoon;

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

public class Main_백준_23290_마법사상어와복제_골드1_2796ms {
	private static int[] dr = {0,-1,-1,-1,0,1,1,1};
	private static int[] dc = {-1,-1,0,1,1,1,0,-1}; // 물고기 이동용
	private static int[] sdr = {0,-1,0,1,0};
	private static int[] sdc = {0,0,-1,0,1}; // 상어 이동용
	private static int[] route = new int[3]; // 루트 완탐용
	private static int[][] bestRoute = new int[3][2]; // 최상 루트 저장용
	private static ArrayList<fish>[][] map = new ArrayList[5][5];
	private static int[][] smell = new int[5][5]; // 냄새 저장용
	private static int sharkr, sharkc, countFish=0, priority = 445;
	public static void main(String[] args) throws IOException {
		for (int i = 1; i <= 4; i++) {
			for (int j = 1; j <= 4; j++) {
				map[i][j] = new ArrayList<fish>();
			}
		}
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer stk = new StringTokenizer(br.readLine());
		int M = Integer.parseInt(stk.nextToken()); // 물고기수 1~10
		int S = Integer.parseInt(stk.nextToken()); // 마법횟수 1~100
		for (int i = 0; i < M; i++) {
			stk = new StringTokenizer(br.readLine());
			int fx = Integer.parseInt(stk.nextToken()); // 물고기 r
			int fy = Integer.parseInt(stk.nextToken()); // 물고기 c
			int d = Integer.parseInt(stk.nextToken()) - 1; // 물고기 방향 (1빼준다.)
			map[fx][fy].add(new fish(fx, fy, d));
		}
		stk = new StringTokenizer(br.readLine());
		sharkr = Integer.parseInt(stk.nextToken());
		sharkc = Integer.parseInt(stk.nextToken());
		
		for (int spell = 0; spell < S; spell++) {
      // 주문 횟수만큼 실행
			moveFish();
		}
		
		// 최종적으로 남아있는 물고기 수 세자.
		int result = 0;
		for (int i = 1; i <= 4; i++) {
			for (int j = 1; j <= 4; j++) {
				for (int k = 0; k < map[i][j].size(); k++) {
					result++;
				}
			}
		}
		System.out.println(result);
	} // 메인 끝

	private static void moveFish() {
		// 잠시 저장할 tmap 생성, 현재 물고기 상태 저장
    // tmap의 존재 이유는 복제가 늦게 일어나기 때문.
    // 물고기를 옮기고, 상어도 옮기고 냄새도 뿌려준 뒤에야 복제된다.
		ArrayList<fish>[][] tmap = new ArrayList[5][5];
		for (int i = 1; i <= 4; i++) {
			for (int j = 1; j <= 4; j++) {
				tmap[i][j] = new ArrayList<fish>();
				for (int k = 0; k < map[i][j].size(); k++) {
					tmap[i][j].add(new fish(map[i][j].get(k).getR(), map[i][j].get(k).getC(), map[i][j].get(k).getDir()));
				}
			}
		}
		
		// 현재 물고기들 1칸씩 전진, saveMove에 움직인 좌표랑 dir 저장했다가 한번에 map에 적용
		ArrayList<fish> saveMove = new ArrayList<fish>();
		// 각 칸 돌면서 물고기 이동시키자.
		for (int i = 1; i <= 4; i++) {
			for (int j = 1; j <= 4; j++) {
				// map 에 있는 애들 초기화. 초기화해야 물고기가 이동한 것과 같은 결과가 나옴.
				map[i][j].clear();
				// tmap 에 있는거 꺼내쓰자.
				for (int k = 0; k < tmap[i][j].size(); k++) {
					int tr = tmap[i][j].get(k).getR();
					int tc = tmap[i][j].get(k).getC();
					int tdir = tmap[i][j].get(k).getDir();
					// 회전 실시
					for (int l = 0, ddir = 8; l < 8; l++, ddir--) {
						// 반시계 방향으로 회전
						int ndir = (tdir + ddir) % 8;
						int nr = tr + dr[ndir];
						int nc = tc + dc[ndir];
						// 창밖으로 나가냐? 봤더니 냄새가 있는곳이냐? 봤더니 상어가 있는 곳이냐? 그러면 안됨.
						if (nr<1 || nr>=5 || nc<1 || nc>=5 || smell[nr][nc] != 0 || (nr==sharkr && nc==sharkc)) {
							// 8방 다 뒤져봐도 갈 데가 없다면
							if (l == 7) {
								saveMove.add(new fish(tr, tc, tdir));
								break;
							} 
							else continue;
						}
						// 아니라면 한 칸 이동한 좌표 saveMove에 저장.
						saveMove.add(new fish(nr, nc, ndir));
						// 한 번 이동한 애는 더 회전하지 않음.
						break;
					}
				}
			}
		}
		
		// 이동 저장한거 map에 적용시킨다.
		for (int i = 0; i < saveMove.size(); i++) {
			int r = saveMove.get(i).getR();
			int c = saveMove.get(i).getC();
			int dir = saveMove.get(i).getDir();
			map[r][c].add(new fish(r, c, dir));
		}
		
		// 상어의 최적의 이동 경로 계산
		priority = 445;
		countFish = 0;
		findRoute(0);
		
		// 최적의 루트를 걸어간 길에 물고기 수거하고 냄새 남겨놓기.
		for (int i = 0; i < bestRoute.length; i++) {
			int r = bestRoute[i][0];
			int c = bestRoute[i][1];
      // smell 을 3으로 해줘야 곧바로 냄새가 1로 줄면서 마법 2번까지 지속된다.
			if (!map[r][c].isEmpty()) smell[r][c] = 3;
			map[r][c].clear();
		}
		
		// 상어를 옮겨준다.
		sharkr = bestRoute[2][0];
		sharkc = bestRoute[2][1];
		
		// 냄새를 1씩 줄인다. 이미 0이면 안줄이고.
		for (int i = 0; i < smell.length; i++) {
			for (int j = 0; j < smell[i].length; j++) {
				if (smell[i][j] == 0) continue;
				smell[i][j]--;
			}
		}
		
		// 복제가 완료된다.
		for (int i = 1; i <= 4; i++) {
			for (int j = 1; j <= 4; j++) {
				for (int k = 0; k < tmap[i][j].size(); k++) {
					map[i][j].add(new fish(tmap[i][j].get(k).getR(), tmap[i][j].get(k).getC(), tmap[i][j].get(k).getDir()));
				}
			}
		}
	}

	private static void findRoute(int cnt) {
		// 444, 443, 442 ..... 113, 112, 111 순으로 탐색.
		// 왜냐면 사전순으로 앞선 것으로 갈아치우기 위해서.
		if (cnt == 3) {
			findBestRoute();
			return;
		}
		for (int i = 4; i >= 1; i--) {
			route[cnt] = i;
			findRoute(cnt + 1);
		}
	}

	private static void findBestRoute() {
		// 임시로 쓸 ttmap 또 만들자..
    // ttmap을 만든 이유는 최적의 루트를 가면서 물고기를 실시간으로 제거해줘야 하기 때문에.
    // 물고기를 실시간으로 제거하지 않으면 한 번 탐색한 곳을 또 방문할 수가 있다.
		ArrayList<fish>[][] ttmap = new ArrayList[5][5];
		for (int i = 1; i <= 4; i++) {
			for (int j = 1; j <= 4; j++) {
				ttmap[i][j] = new ArrayList<fish>();
				for (int k = 0; k < map[i][j].size(); k++) {
					ttmap[i][j].add(new fish(map[i][j].get(k).getR(), map[i][j].get(k).getC(), map[i][j].get(k).getDir()));
				}
			}
		}
    // 이동한 경로를 저장해줄 배열
		int[][] memorizeRoute = new int[3][2];
    // 상어의 위치
		int sr = sharkr;
		int sc = sharkc;
		int cnt = 0;
    // p 변수에 숫자를 String으로 담다가 나중에 Integer로 바꿔서 priority와 비교함.
		String p = "";
		for (int i = 0; i < route.length; i++) {
			int dir = route[i];
			// 4우 3하 2좌 1상
			sr += sdr[dir];
			sc += sdc[dir];
			// 밖으로 나가면 땡
			if (sr<1 || sr>=5 || sc<1 || sc>=5) return;
			// 안나갔으면 이어서, 
			// 그 자리에 물고기 수 센다.
			cnt += ttmap[sr][sc].size();
			// 그리고 그 자리는 비워버린다.
			ttmap[sr][sc].clear();
      // 경로 암기.
			memorizeRoute[i][0] = sr;
			memorizeRoute[i][1] = sc;
      // 우선순위 비교를 위한 행위
			p = p.concat(Integer.toString(dir));
		}
		// 역대급으로 cnt가 높고, 우선으로 앞서면 bestRoute를 갱신한다.
		int pNum = Integer.parseInt(p);
		if (cnt >= countFish && pNum < priority) {
			bestRoute[0][0] = memorizeRoute[0][0];
			bestRoute[0][1] = memorizeRoute[0][1];
			bestRoute[1][0] = memorizeRoute[1][0];
			bestRoute[1][1] = memorizeRoute[1][1];
			bestRoute[2][0] = memorizeRoute[2][0];
			bestRoute[2][1] = memorizeRoute[2][1]; 
      // 얘내들도 갱신함.
			countFish = cnt;
			priority = pNum;
		}
	}

	static class fish {
		int r;
		int c;
		int dir;
		
		public int getR() {
			return r;
		}
		public int getC() {
			return c;
		}
		public int getDir() {
			return dir;
		}
		public fish(int r, int c, int dir) {
			this.r = r;
			this.c = c;
			this.dir = dir;
		}
	}
}

 

jdk 11로 올라가면서 자동지원하지 않는다.

 

https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api/2.4.0-b180830.0359

 

여기 들어가서

난 Gradle 을 쓰므로 Gradle용 복사해서 build.gradle의 dependencies안에 붙여넣기 해줬다.

1978년 C와 UNIX를 개발한

데니스 리치(Dennis Ritchie)와 브라이언 커니핸(Brian Wilson Kernighan)

두 사람이 쓴 "The C Program Language" 교재에서 유래하였다.

 

이 책의 첫 예제가 hello, world 출력이었다.

 

이 예제가 유명해지면서 지금까지도 첫 예제는 Hello World를 출력하는 것으로 이어지고있다.

'TIL' 카테고리의 다른 글

정규표현식  (0) 2022.10.12
csv insert with MySQL (Load data infile) 방법  (0) 2022.08.30
Docker 를 왜 쓸까  (0) 2021.12.25
CSR vs SSR  (2) 2021.12.24
ORM (Object Relational Mapping)  (0) 2021.12.23

Docker는 2013년 등장한 컨테이너 기반 가상화 도구이다.

 

로컬에서 개발하던 프로젝트를 배포하고싶을때 AWS서버에 직접 배포하려면

 - 생소한 리눅스언어 접해야함

 - 다양한 언어별 환경구성 해야함

 - 의존성 패키지, 라이브러리, 빌드 툴 등등 설치 해야함

 - 매번 새로운 버전이 출시되면 버전이슈 발생함

 - 이러한 과정을 수동으로 매번 한다면 작업자의 실수를 야기할 수도 있음.

 

어렵다.

 

도커를 이용하면

 - OS를 포함한 설치 과정을 Dickerfile로 문서화함

 - 수정 이력은 버전 관리가 되어 변경사항을 확인 가능 - 롤백 편함

 - 개발환경에 필요한 환경 구성이 편리해짐. - 레고 블럭처럼 서비스를 쌓아서 사용

 - 윈도우/맥/리눅스 가리지 않고 동일하게 동작하게 가능

 - 안전하게 격리된 컨테이너 환경에서 구동함

'TIL' 카테고리의 다른 글

csv insert with MySQL (Load data infile) 방법  (0) 2022.08.30
왜 Hello World ?  (0) 2021.12.25
CSR vs SSR  (2) 2021.12.24
ORM (Object Relational Mapping)  (0) 2021.12.23
TIL이란?  (0) 2021.12.23

CSR (Client Side Rendering)

 - Browser에서 자바스크립트에 의해 view를 동적으로 생성.

 - SSR보다 상대적으로 빠르다.

 - 대신 최초 접속 시 모든 자바스크립트와 static파일을 가져와야한다.

 - 따라서 최초 접속 시 로딩은 SSR보다 느리다.

 

SSR (Server side Rendering)

 - 웹서버에서 View를 생성한다.

 - 페이지가 전환될 때 마다 client가 서버에 View 요청을 함.

 - 서버는 그것을 client에 응답.

 - 때문에 view 전환 속도가 CSR에 비해 느리다.

 - 페이지 전환 요청이 빈번할수록 서버 부하가 커진다.

 

Vue 와 React 는 CSR 방식으로 View를 만듬.

 - 얘내 둘은 SPA (Single Page Application) framework 이다.

PHP는 SSR 방식으로 만듬.

 - PHP는 MPA (Multi Page Application) framework 이다.

'TIL' 카테고리의 다른 글

csv insert with MySQL (Load data infile) 방법  (0) 2022.08.30
왜 Hello World ?  (0) 2021.12.25
Docker 를 왜 쓸까  (0) 2021.12.25
ORM (Object Relational Mapping)  (0) 2021.12.23
TIL이란?  (0) 2021.12.23

ORM (Object Relational Mapping)

 - 사물을 추상화시켜 이해하려는 OOP적 사고방식과 DataModel을 정형화하여 관리하려는 RDB사이를 연결할 계층의 역할로 제시된 패러다임.

 - RDB (Relational DataBase) 관계형 데이터베이스

 - OOP (Object-Oriented Programming) 객체지향 프로그래밍

 - RBD의 모델을 OOP에 Entity형태로 투영시키는 방식을 사용.

 - Database 및 DB Connector에 따라 다라질 수 있는 데이터 매핑 구조를 객체지향 형태로 통일시켜 SQL구조의 Database를 OOP 구조의 형태로 매핑시킴.

 

 - 이러한 ORM을 구현하는 대표적인 프레임워크가 Hibernate

 - 이를 Java 표준 방식으로 정의한 것이 JPA

 - 실무에서 개발할 때에는 JPA와 Hibernate를 같이 사용한다.

 

 

ORM이 흔히 겪는 RDB와 OOP 사이의 아직 풀지 못한 숙제

 1. RDB 데이터 타입은 Vendor 마다 다르며, 더이상 정규화가 힘듬

 2. 하위 타입 문제 (RDB에는 상속의 개념이 없다.)

 3. 동일성 문제 (Java의 경우 Equals로 평가 가능하지만 DB는 PK 기준으로 함)

 4. 연관 관계 (FK는 연관의 방향성을 갖지 못하기 때문에 N:N 모델의 경우 Link테이블을 도입해야 함)

 5. 데이터 검색 (RDB는 한 번에 많이 가져올지 빈번하게 데이터를 가져올지를 고민해야함.)

 

 

출처: https://jins-dev.tistory.com/entry/ORMObject-Relational-Mapping%EC%9D%B4%EB%9E%80-ORM-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84%EC%9D%98-%EA%B0%9C%EB%85%90

'TIL' 카테고리의 다른 글

csv insert with MySQL (Load data infile) 방법  (0) 2022.08.30
왜 Hello World ?  (0) 2021.12.25
Docker 를 왜 쓸까  (0) 2021.12.25
CSR vs SSR  (2) 2021.12.24
TIL이란?  (0) 2021.12.23

처음 IntelliJ 를 설치할 때 이 기능을 쓸건지 말건지 선택하는 체크박스가 있는데

체크하는걸 놓친 경우.

 

실행 -> regedit -> 레지스트리 편집기 열기

 

HKEY_CLASSES_ROOT\Directory\Background\shell

에다가 새로만들기 -> 키 선택.

폴더처럼 생성이 될건데, 이름을 IntelliJ IDEA 로 변경.

 

그러면 내부에 자동으로 (기본값) 이 생겨난다.

더블클릭해서 값 데이터에 Open Folder as IntelliJ IDEA Project 이렇게 친다.

 

 

그리고 새로만들기 -> 문자열 값 선택,

이름을 Icon 으로 바꾸고, 자신의 IntelliJ IDEA가 설치된 폴더를 찾는다.

본인같은 경우는 기본 경로로 선택했었다.

 

 

내부에 키를 하나 더 생성, 이름은 command로 한다.

(기본값) 을 더블클릭해서 값을 아까 "적은 경로" 한 칸 띄고 "%V" 로 작성해준다.

 

 

요렇게.

 

비슷하게 vscode도 설정할 수 있다.

 

Today I Learned 의 줄임말이더라.

'TIL' 카테고리의 다른 글

csv insert with MySQL (Load data infile) 방법  (0) 2022.08.30
왜 Hello World ?  (0) 2021.12.25
Docker 를 왜 쓸까  (0) 2021.12.25
CSR vs SSR  (2) 2021.12.24
ORM (Object Relational Mapping)  (0) 2021.12.23

+ Recent posts