diff --git a/.gitignore b/.gitignore index 2298b78..b43118e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Input, Output *.in *.out +input.txt +output.txt +answer.txt ### Eclipse ### .metadata diff --git a/problems/SWEA/p1952/Solution.java b/problems/SWEA/p1952/Solution.java new file mode 100644 index 0000000..953b5cc --- /dev/null +++ b/problems/SWEA/p1952/Solution.java @@ -0,0 +1,159 @@ +/* + * {풀이 하는 중} (1952) [모의 SW 역량테스트] 수영장 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV5PpFQaAQMDFAUq&categoryId=AV5PpFQaAQMDFAUq&categoryType=CODE&problemTitle=1952&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +import java.io.*; +import java.util.*; + +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer input; + + // -------------------------------------------------------- + + public static void main(String[] args) throws IOException { + final int testCount = Integer.parseInt(reader.readLine().trim()); + + for (int testCase = 1; testCase <= testCount; testCase++) { + new Solution(testCase).run(); + } + } + + // -------------------------------------------------------- + + static final int TICKET_TYPE_LEN = 4; + static final int MONTH_LEN = 12; + + static final int ONE_DAY_TICKET = 0; + static final int ONE_MONTH_TICKET = 1; + static final int THREE_MONTH_TICKET = 2; + static final int ONE_YEAR_TICKET = 3; + + int testCase; + int bestPrice; + + boolean noPlan; + int[] priceArr; + int[] planArr; + + int[] oneDayTicketArr; + boolean[] monthTicketArr; + + public Solution(int testCase) { + this.testCase = testCase; + } + + public void run() throws IOException { + input(); + solve(); + print(); + } + + private void input() throws IOException { + getLine(); + priceArr = new int[TICKET_TYPE_LEN]; + for (int index = 0; index < TICKET_TYPE_LEN; index++) { + priceArr[index] = Integer.parseInt(input.nextToken()); + } + + getLine(); + noPlan = true; + planArr = new int[MONTH_LEN]; + for (int index = 0; index < MONTH_LEN; index++) { + planArr[index] = Integer.parseInt(input.nextToken()); + if (planArr[index] != 0) noPlan = false; + } + } + + private void solve() { + // 만약 이용계획이 없는 경우 bestPrice는 0이 된다. + if (noPlan) { + bestPrice = 0; + return; + } + + bestPrice = priceArr[ONE_YEAR_TICKET]; // 1년 이용권 + + oneDayTicketArr = new int[MONTH_LEN]; + monthTicketArr = new boolean[MONTH_LEN]; + + offset = bestPrice * 2; + cache = new boolean[13 * offset]; + + searchBestPrice(0, 0); + } + + int offset; + boolean[] cache; + + private void searchBestPrice(int month, int currentPrice) { + if (month > MONTH_LEN || currentPrice >= bestPrice) return; + + int cacheKey = month * offset + currentPrice; + // System.out.printf("searchBestPrice(%d, %d)\n", month, currentPrice); + if (cache[cacheKey]) return; + cache[cacheKey] = true; + + while ( (month < MONTH_LEN) && + (monthTicketArr[month] || oneDayTicketArr[month] >= planArr[month]) + ) { + month++; + } + + // 기저조건 + if (month >= MONTH_LEN) { + if (currentPrice < bestPrice) bestPrice = currentPrice; + cache[cacheKey] = true; + return; + } + + // System.out.printf("[%d] searchBestPrice(%d, %d)\n", testCase, month, currentPrice); + + int price; + + // 1일 이용권 + price = currentPrice + priceArr[ONE_DAY_TICKET]; + if (price < bestPrice) { + oneDayTicketArr[month]++; + if (oneDayTicketArr[month] >= planArr[month]) { + searchBestPrice(month + 1, price); + } else { + searchBestPrice(month, price); + } + oneDayTicketArr[month]--; + } + + // 1달 이용권 + price = currentPrice + priceArr[ONE_MONTH_TICKET]; + if (price < bestPrice) { + monthTicketArr[month] = true; + searchBestPrice(month + 1, price); + monthTicketArr[month] = false; + } + + // 3달 이용권 + price = currentPrice + priceArr[THREE_MONTH_TICKET]; + if (price < bestPrice) { + for (int m = month; m < month + 2 && m < MONTH_LEN; m++) monthTicketArr[m] = true; + searchBestPrice(month + 3, price); + for (int m = month; m < month + 2 && m < MONTH_LEN; m++) monthTicketArr[m] = false; + } + + cache[cacheKey] = true; + } + + private void print() throws IOException { + writer.write("#" + testCase); + writer.write(" " + bestPrice); + writer.write("\n"); + writer.flush(); + } + + // -------------------------------------------------------- + + private void getLine() throws IOException { + input = new StringTokenizer(reader.readLine().trim()); + } +} diff --git a/problems/SWEA/p1952/answer.txt b/problems/SWEA/p1952/answer.txt new file mode 100644 index 0000000..8e2c28a --- /dev/null +++ b/problems/SWEA/p1952/answer.txt @@ -0,0 +1,10 @@ +#1 110 +#2 100 +#3 400 +#4 530 +#5 430 +#6 1080 +#7 1840 +#8 800 +#9 1980 +#10 2260 diff --git a/problems/SWEA/p1952/input.txt b/problems/SWEA/p1952/input.txt new file mode 100644 index 0000000..2a44a02 --- /dev/null +++ b/problems/SWEA/p1952/input.txt @@ -0,0 +1,21 @@ +10 +10 40 100 300 +0 0 2 9 1 5 0 0 0 0 0 0 +10 100 50 300 +0 0 0 0 0 0 0 0 6 2 7 8 +10 70 180 400 +6 9 7 7 7 5 5 0 0 0 0 0 +10 70 200 550 +0 0 0 0 8 9 6 9 6 9 8 6 +10 80 200 550 +0 8 9 15 1 13 2 4 9 0 0 0 +10 130 360 1200 +0 0 0 15 14 11 15 13 12 15 10 15 +10 180 520 1900 +0 18 16 16 19 19 18 18 15 16 17 16 +10 100 200 1060 +12 9 11 13 11 8 6 12 8 7 15 6 +10 170 500 1980 +19 18 18 17 15 19 19 16 19 15 17 18 +10 200 580 2320 +12 28 24 24 29 25 23 26 26 28 27 22 diff --git a/problems/SWEA/p1952/output.txt b/problems/SWEA/p1952/output.txt new file mode 100644 index 0000000..7656bfa --- /dev/null +++ b/problems/SWEA/p1952/output.txt @@ -0,0 +1,9 @@ +#1 100 +#2 50 +#3 180 +#4 200 +#5 200 +#6 360 +#7 520 +#8 200 +#9 500 diff --git a/problems/SWEA/p2806/Solution.java b/problems/SWEA/p2806/Solution.java new file mode 100644 index 0000000..b0fd232 --- /dev/null +++ b/problems/SWEA/p2806/Solution.java @@ -0,0 +1,226 @@ +/* + * (2806) N-Queen + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AV7GKs06AU0DFAXB&categoryId=AV7GKs06AU0DFAXB&categoryType=CODE&problemTitle=2806&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +import java.io.*; +import java.util.*; + +/** + * SW Expert Academy - 2806. N-Queen + * @author YeJun, Jung + * + * @see #main(String[] args) + * 1. 테스트케이스를 입력받는다. + * 2. 솔루션을 실행한다. + * + * @see #input() + * 3. 보드의 크기이자 퀸의 개수인 N을 입력받는다. + * + * @see #solve() + * 4. 멤버변수를 초기화한다. + * 5. 퀸을 배치할 수 있는 경우의 수에 대해서 탐색을 시작한다. + * + * @see #search(int nQueen, int y) + * 6. 기저조건을 검사한다. + * 6-1. 기저조건을 달성하면 answer을 +1 한다. + * 7. 현재 y위치에서 board의 마지막 위치까지 탐색한다. + * 7-1. 지금 위치에 퀸을 배치한다. + * 7-1-1. 지금 위치에 퀸을 배치할 수 없다면 다음 위치로 이동한다. + * 7-2. 다음 퀸 배치를 위한 탐색을 재귀함수로 진행한다. + * 7-3. 배치해 두었던 퀸을 삭제한다. + * + * @see #putQueen(int x, int y) + * 8. 주어진 위치(x, y)에 퀸을 배치한다. + * 8-1. 주어진 위치에 이미 퀸이 존재한다면 false(불가능)을 반환한다. + * 8-2. 변수를 초기화한다. + * 8-3. 퀸의 이동범위에 대해서... + * 8-3-1. 주어진 위치에 퀸을 배치했을때 이미 배치되어 있는 퀸을 잡을 수 있다면 + * 8-3-1-1. 퀸을 배치할 수 없다. + * 8-3-2. 퀸이 이동가능한 위치를 표시한다. + * 8-3-3. 계속해서 다음 퀸의 이동가능한 위치를 검토한다. + * 8-4. 만약, 이전에 배치된 퀸을 잡을 수 있는 위치에 있다면... + * 8-4-1. 지금까지 표시한 퀸의 이동가능한 위치들을 롤백한다. + * 8-4-2. false(불가능)을 반환한다. + * 8-5. 주어진 위치에 퀸을 배치한다. + * 8-6. true(배치 성공함)을 반환한다. + * + * @see #removeQueen(int x, int y) + * 9. 주어진 위치에 있는 퀸을 제거하고, 해당 퀸의 이동가능한 범위를 board에서 삭제한다. + * + * @see #isInsideBoard(int x, int y) + * 10. 주어진 위치가 board 범위 안에 있는지 검사한다. + * + * @see print() + * 11. answer를 화면에 출력한다. + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + + // -------------------------------------------------------- + + public static void main(String[] args) throws IOException { + // 1. 테스트케이스를 입력받는다. + final int testCount = Integer.parseInt(reader.readLine().trim()); + + for (int testCase = 1; testCase <= testCount; testCase++) { + // 2. 솔루션을 실행한다. + new Solution(testCase).run(); + } + } + + // -------------------------------------------------------- + + final static int[] QUEEN_DIR_X = { 0, 1, 1, 1, 0, -1, -1, -1 }; + final static int[] QUEEN_DIR_Y = { -1, -1, 0, 1, 1, 1, 0, -1 }; + final static int QUEEN_DIR_LEN = 8; + + int testCase; + int answer; + + int N; + int[][] board; + + public Solution(int testCase) { + this.testCase = testCase; + } + + public void run() throws IOException { + input(); + solve(); + print(); + } + + private void input() throws IOException { + // 3. 보드의 크기이자 퀸의 개수인 N을 입력받는다. + N = Integer.parseInt(reader.readLine().trim()); + } + + private void solve() { + // 4. 멤버변수를 초기화한다. + answer = 0; + board = new int[N][N]; + + // 5. 퀸을 배치할 수 있는 경우의 수에 대해서 탐색을 시작한다. + search(N, 0); + } + + private void search(int nQueen, int y) { + // 6. 기저조건을 검사한다. + if (nQueen == 0) { + // 6-1. 기저조건을 달성하면 answer을 +1 한다. + answer++; + + return; + } + + // 7. 현재 y위치에서 board의 마지막 위치까지 탐색한다. + for (int cy = y; cy < N; cy++) { + for (int cx = 0; cx < N; cx++) { + // 7-1. 지금 위치에 퀸을 배치한다. + // 7-1-1. 지금 위치에 퀸을 배치할 수 없다면 다음 위치로 이동한다. + if (!putQueen(cx, cy)) continue; + + // 7-2. 다음 퀸 배치를 위한 탐색을 재귀함수로 진행한다. + search(nQueen - 1, cy + 1); + + // 7-3. 배치해 두었던 퀸을 삭제한다. + removeQueen(cx, cy); + } + } + } + + private boolean putQueen(int x, int y) { + // 8. 주어진 위치(x, y)에 퀸을 배치한다. + + // 8-1. 주어진 위치에 이미 퀸이 존재한다면 false(불가능)을 반환한다. + if (board[y][x] != 0) return false; + + // 8-2. 변수를 초기화한다. + boolean available = true; + int count = 0; + + // 8-3. 퀸의 이동범위에 대해서... + for (int dir = 0; dir < QUEEN_DIR_LEN; dir++) { + int cx = x + QUEEN_DIR_X[dir]; + int cy = y + QUEEN_DIR_Y[dir]; + + while (isInsideBoard(cx, cy)) { + // 8-3-1. 주어진 위치에 퀸을 배치했을때 이미 배치되어 있는 퀸을 잡을 수 있다면 + if (board[cy][cx] < 0) { + // 8-3-1-1. 퀸을 배치할 수 없다. + available = false; + break; + } + + // 8-3-2. 퀸이 이동가능한 위치를 표시한다. + board[cy][cx]++; + count++; + + // 8-3-3. 계속해서 다음 퀸의 이동가능한 위치를 검토한다. + cx += QUEEN_DIR_X[dir]; + cy += QUEEN_DIR_Y[dir]; + } + } + + // 8-4. 만약, 이전에 배치된 퀸을 잡을 수 있는 위치에 있다면... + if (!available) { + // 8-4-1. 지금까지 표시한 퀸의 이동가능한 위치들을 롤백한다. + for (int dir = 0; dir < QUEEN_DIR_LEN && count > 0; dir++) { + int cx = x + QUEEN_DIR_X[dir]; + int cy = y + QUEEN_DIR_Y[dir]; + + while (isInsideBoard(cx, cy)) { + board[cy][cx]--; + count--; + + cx += QUEEN_DIR_X[dir]; + cy += QUEEN_DIR_Y[dir]; + } + } + + // 8-4-2. false(불가능)을 반환한다. + return false; + } + + // 8-5. 주어진 위치에 퀸을 배치한다. + board[y][x] = -1; + + // 8-6. true(배치 성공함)을 반환한다. + return true; + } + + private void removeQueen(int x, int y) { + // 9. 주어진 위치에 있는 퀸을 제거하고, 해당 퀸의 이동가능한 범위를 board에서 삭제한다. + + board[y][x] = 0; + + for (int dir = 0; dir < QUEEN_DIR_LEN; dir++) { + int cx = x + QUEEN_DIR_X[dir]; + int cy = y + QUEEN_DIR_Y[dir]; + + while (isInsideBoard(cx, cy)) { + board[cy][cx]--; + + cx += QUEEN_DIR_X[dir]; + cy += QUEEN_DIR_Y[dir]; + } + } + } + + private boolean isInsideBoard(int x, int y) { + // 10. 주어진 위치가 board 범위 안에 있는지 검사한다. + return x >= 0 && x < N && y >= 0 && y < N; + } + + private void print() throws IOException { + // 11. answer를 화면에 출력한다. + writer.write("#" + testCase); + writer.write(" " + answer); + writer.write("\n"); + writer.flush(); + } + + // -------------------------------------------------------- +} diff --git a/problems/SWEA/p5648/Solution.java b/problems/SWEA/p5648/Solution.java new file mode 100644 index 0000000..62a560e --- /dev/null +++ b/problems/SWEA/p5648/Solution.java @@ -0,0 +1,223 @@ +/* + * (5648) [모의 SW 역량테스트] 원자 소멸 시뮬레이션 + * https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRFInKex8DFAUo&categoryId=AWXRFInKex8DFAUo&categoryType=CODE&problemTitle=5648&orderBy=FIRST_REG_DATETIME&selectCodeLang=ALL&select-1=&pageSize=10&pageIndex=1 + */ + +import java.io.*; +import java.util.*; + +/** + * SW Expert Academy - 5648. [모의 SW 역량테스트] 원자 소멸 시뮬레이션 + * @author YeJun, Jung + * + * @see #main(String[] args) + * 1. 테스트케이스를 입력받는다. + * 2. 솔루션을 실행한다. + * + * @see #input() + * 3. 원자 개수를 입력받는다. + * 4. 원자 목록을 보관할 리스트 atomList를 초기화한다. + * 5. 원자들을 입력받아 atomList에 저장한다. + * + * @see #solve() + * 6. 멤버변수를 초기화한다. + * 7. 시뮬레이션을 시작한다. + * + * @see #runSimuration() + * 8. 이론상 가능한 최대 횟수만큼 시뮬레이션을 실시하되, 모든 원자가 충돌하여 + * 시뮬레이션할 원자가 없는 경우에는 조기에 종료한다. + * + * @see #nextStep() + * 9. 리턴 변수를 초기화한다. + * 10. 아직 충돌하지 않은 원자들을 이동시키고, 그 위치를 기록한다. + * 10-1. 이론적으로 가능한 범위 안에서 원자 위치를 index로 변환한다. + * 10-2. 범위를 벗어난다면 해당 원소를 소멸 시킨다. + * 10-3. 이동 후 원자의 위치를 기록한다. + * 11. 모든 원자가 충돌하여 소멸한 경우 시뮬레이션을 중단한다. + * 12. 원자들 간의 충돌을 판단하여 원자를 소멸시키고, 발산한 에너지를 기록한다. + * 13. board 배열을 초기화한다. + * + * @see #print() + * + */ +public class Solution { + static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out)); + static StringTokenizer input; + + // -------------------------------------------------------- + + public static void main(String[] args) throws IOException { + // 1. 테스트케이스를 입력받는다. + final int testCount = Integer.parseInt(reader.readLine().trim()); + + for (int testCase = 1; testCase <= testCount; testCase++) { + // 2. 솔루션을 실행한다. + new Solution(testCase).run(); + } + } + + // -------------------------------------------------------- + + private final int OFFSET = 2000; + private final int MAX_RANGE = OFFSET * 2; + + int testCase; + int raisedEnergy; // answer + + int atomCount; + List atomList; + + int[][] board; + + public Solution(int testCase) { + this.testCase = testCase; + } + + public void run() throws IOException { + input(); + solve(); + print(); + } + + private void input() throws IOException { + // 3. 원자 개수를 입력받는다. + atomCount = Integer.parseInt(reader.readLine().trim()); + // 4. 원자 목록을 보관할 리스트 atomList를 초기화한다. + atomList = new ArrayList<>(atomCount); + + // 5. 원자들을 입력받아 atomList에 저장한다. + for (int count = 0; count < atomCount; count++) { + atomList.add(Atom.fromReader(reader)); + } + } + + private void solve() { + // 6. 멤버변수를 초기화한다. + raisedEnergy = 0; + board = new int[MAX_RANGE + 1][MAX_RANGE + 1]; + + // 7. 시뮬레이션을 시작한다. + runSimuration(); + } + + private void runSimuration() { + // 원자들의 초기위치는 -1000 ~ 1000인데, 0.5이동 때문에 초기위치에 x2되어 + // -2000 ~ 2000가 초기위치가 된다. + // 가장자리에 있는 원소들을 고려할때, 최대 4000번만 시뮬레이션하고 종료하면 된다. + final int last = 4000; + + // 8. 이론상 가능한 최대 횟수만큼 시뮬레이션을 실시하되, 모든 원자가 충돌하여 + // 시뮬레이션할 원자가 없는 경우에는 조기에 종료한다. + for (int count = 0; count < last; count++) { + if (nextStep() == 0) break; + } + } + + private int nextStep() { + // 9. 리턴 변수를 초기화한다. + int activeAtoms = 0; + + // 10. 아직 충돌하지 않은 원자들을 이동시키고, 그 위치를 기록한다. + for (Atom atom : atomList) { + if (atom.energy == 0) continue; + + atom.moveNext(); + + // 10-1. 이론적으로 가능한 범위 안에서 원자 위치를 index로 변환한다. + int mx = atom.x + OFFSET; + int my = atom.y + OFFSET; + + // 10-2. 범위를 벗어난다면 해당 원소를 소멸 시킨다. + if (mx < 0 || mx > MAX_RANGE || my < 0 || my > MAX_RANGE) { + atom.energy = 0; + continue; + } + + // 10-3. 이동 후 원자의 위치를 기록한다. + board[mx][my] += atom.energy; + activeAtoms++; + } + + // 11. 모든 원자가 충돌하여 소멸한 경우 시뮬레이션을 중단한다. + if (activeAtoms == 0) return 0; + + // 12. 원자들 간의 충돌을 판단하여 원자를 소멸시키고, 발산한 에너지를 기록한다. + for (Atom atom : atomList) { + if (atom.energy == 0) continue; + + int mx = atom.x + OFFSET; + int my = atom.y + OFFSET; + + if (board[mx][my] > atom.energy) { + raisedEnergy += atom.energy; + atom.energy = 0; + } + } + + // 13. board 배열을 초기화한다. + clearBoard(); + + return activeAtoms; + } + + private void clearBoard() { + for (Atom atom : atomList) { + int mx = atom.x + OFFSET; + int my = atom.y + OFFSET; + if (mx >= 0 && mx <= MAX_RANGE && my >= 0 && my <= MAX_RANGE) { + board[mx][my] = 0; + } + } + } + + private void print() throws IOException { + writer.write("#" + testCase); + writer.write(" " + raisedEnergy); + writer.write("\n"); + writer.flush(); + } + + // -------------------------------------------------------- + + static class Atom { + static final int[] DIR_X = { 0, 0, -1, 1 }; + static final int[] DIR_Y = { 1, -1, 0, 0 }; + + int x; + int y; + int dir; + int energy; + + public Atom(int x, int y, int dir, int energy) { + this.x = x; + this.y = y; + this.dir = dir; + this.energy = energy; + } + + public static Atom fromReader(BufferedReader reader) throws IOException { + getLine(); + int x = Integer.parseInt(input.nextToken()) * 2; // 0.5 시간에 충돌을 처리하기 위해서 x2 한다. + int y = Integer.parseInt(input.nextToken()) * 2; // 0.5 시간에 충돌을 처리하기 위해서 x2 한다. + int dir = Integer.parseInt(input.nextToken()); + int energy = Integer.parseInt(input.nextToken()); + + return new Atom(x, y, dir, energy); + } + + public void moveNext() { + int nextX = x + DIR_X[dir]; + int nextY = y + DIR_Y[dir]; + + x = nextX; + y = nextY; + } + } + + // -------------------------------------------------------- + + private static void getLine() throws IOException { + input = new StringTokenizer(reader.readLine().trim()); + } +}