{ + int id; + int lx, ly; + int rx, ry; + Listlist; + + Group(int id, int lx, int ly, int rx, int ry) { + this.id = id; + this.lx = lx; + this.ly = ly; + this.rx = rx; + this.ry = ry; + list = new ArrayList<>(); + } + public int compareTo(Group o) { + if(this.list.size() != o.list.size()) return Integer.compare(o.list.size(), this.list.size()); + return Integer.compare(this.id, o.id); + } + } + static Map groupCount; + static PriorityQueue groups; + static void findGroup() { + groupCount = new HashMap<>(); + groups = new PriorityQueue<>(); + /** + * board 의 최대 크기가 15 x 15 + * => full scan 가능 + */ + boolean[][] visited = new boolean[n][n]; + for(int x=0; x q = new ArrayDeque<>(); + + int id = board[x][y]; + Group group = new Group(id, x, y, x, y); + groupCount.put(id, groupCount.getOrDefault(id, 0)+1); + group.list.add(new int[] {x, y}); + q.offer(new int[] {x, y}); + visited[x][y] = true; + + while(!q.isEmpty()) { + int[] cur = q.poll(); + for(int dir=0; dir<4; dir++) { + int nx = cur[0] + dx[dir]; + int ny = cur[1] + dy[dir]; + if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue; + if(visited[nx][ny]) continue; + if(board[nx][ny] != id) continue; + + visited[nx][ny] = true; + q.offer(new int[] {nx, ny}); + group.list.add(new int[] {nx, ny}); + group.lx = Math.min(group.lx, nx); + group.ly = Math.min(group.ly, ny); + group.rx = Math.max(group.rx, nx); + group.ry = Math.max(group.ry, ny); + } + } + groups.offer(group); + } + static void moveNewBoard() { + int[][] temp = new int[n][n]; + while(!groups.isEmpty()) { + Group group = groups.poll(); + if(groupCount.get(group.id) > 1) continue; // 둘로 쪼개진 그룹은 패스 + + int[] newLocation = findNewLocation(temp, group); + if(newLocation == null) continue; + /** + * 새로운 위치와, 좌하단 위치의 상대거리를 구해서 모두 이동 + */ + int mx = group.lx - newLocation[0]; + int my = group.ly - newLocation[1]; + + for(int[] point : group.list) { + int nx = point[0] - mx; + int ny = point[1] - my; + temp[nx][ny] = group.id; + } + } + board = temp; + } + static int[] findNewLocation(int[][] temp, Group group) { + int h = group.rx - group.lx + 1; + int w = group.ry - group.ly + 1; + + for(int x=0; x + h <= n; x++) { + for(int y=0; y + w <= n; y++) { +// if(temp[x][y] != 0) continue; => lx, ly, rx, ry 를 실제 그룹이 차지하는 칸으로 기준을 잡지 않았기 때문 + int mx = group.lx - x; + int my = group.ly - y; + boolean canPut = true; + for(int[] point : group.list) { + int nx = point[0] - mx; + int ny = point[1] - my; + if(temp[nx][ny] != 0) { + canPut = false; + break; + } + } + + if(canPut) return new int[] {x, y}; + } + } + return null; + } + static int getScore() { + /** + * 각 그룹의 모든 좌표레서 상하좌우 인접한 그룹이 있는지 확인 + */ + Map groupSize = new HashMap<>(); + for(int x=0; x = n || ny >= n) continue; + if(board[nx][ny] == 0) continue; + if(board[nx][ny] == id) continue; + int oId = board[nx][ny]; + if(adj[id][oId] || adj[oId][id]) continue; + adj[id][oId] = true; + adj[oId][id] = true; + score += (groupSize.get(id) * groupSize.get(oId)); + } + } + } + return score; + } +} diff --git "a/java/src/mar/week3/codetree/\353\257\274\355\212\270\354\264\210\354\275\224\354\232\260\354\234\240_\353\260\225\354\236\254\355\231\230.java" "b/java/src/mar/week3/codetree/\353\257\274\355\212\270\354\264\210\354\275\224\354\232\260\354\234\240_\353\260\225\354\236\254\355\231\230.java" new file mode 100644 index 0000000..d5e374d --- /dev/null +++ "b/java/src/mar/week3/codetree/\353\257\274\355\212\270\354\264\210\354\275\224\354\232\260\354\234\240_\353\260\225\354\236\254\355\231\230.java" @@ -0,0 +1,222 @@ +package mar.week3.codetree; + +import java.util.*; +import java.io.*; + +public class 민트초코우유_박재환 { + static BufferedReader br; + static StringBuilder sb; + public static void main(String[] args) throws IOException { + br = new BufferedReader(new InputStreamReader(System.in)); + sb = new StringBuilder(); + init(); + br.close(); + System.out.println(sb); + } + static final int MINT = 1 << 0; + static final int CHOCO = 1 << 1; + static final int MILK = 1 << 2; + + static StringTokenizer st; + static int n, t; + static int[][] foodBoard; + static int[][] believeBoard; + static void init() throws IOException { + st = new StringTokenizer(br.readLine().trim()); + n = Integer.parseInt(st.nextToken()); + t = Integer.parseInt(st.nextToken()); + // 신앙 음식 + foodBoard = new int[n][n]; + for(int x=0; x 비트 마스킹을 활용해서 표현 + * 민트 : 001 + * 초코 : 010 + * 우유 : 100 + */ + static void solution() { + while(t-- > 0) { + /** + * [아침시간] + * 모든 학생들은 신앙심을 1씩 얻는다. + * => 점심시간과 통합 + */ + afternoon(); + evening(); + finishDay(); + } + } + static class Master implements Comparable { + int x, y; + int food; + int believe; + + Master(int x, int y, int food, int believe) { + this.x = x; + this.y = y; + this.food = food; + this.believe = believe; + } + + public int compareTo(Master o) { + int thisBitCount = Integer.bitCount(this.food); + int otherBitCount = Integer.bitCount(o.food); + + if(thisBitCount == otherBitCount) { + if(this.believe != o.believe) return Integer.compare(o.believe, this.believe); + if(this.x != o.x) return Integer.compare(this.x, o.x); + return Integer.compare(this.y, o.y); + } + return Integer.compare(thisBitCount, otherBitCount); + } + } + static PriorityQueue pq; + static void afternoon() { + /** + * [점심시간] + * 인접한 학생들과 그룹을 형성한다. + * -> 신봉음식이 완전하게 같은 경우에만 그룸을 형성한다. + * + * 그룹에서 대표자 한 명을 선정한다. + * - 신앙심이 가장 큰 사람 + * - 행, 열이 가장 작은 사람 + * + * 대표자를 제외한 그룹원들은 각자 신앙심을 1씩 대표자에게 넘긴다. + * 대표자는 그룹원 수 - 1 만큼 신앙심을 획득한다. + */ + pq = new PriorityQueue<>(); + boolean[][] checked = new boolean[n][n]; + for(int x=0; x q = new ArrayDeque<>(); + int food = foodBoard[x][y]; + + Master master = new Master(x, y, food, believeBoard[x][y]); + int groupSize = 1; + q.offer(new int[] {x, y}); + checked[x][y] = true; + + while(!q.isEmpty()) { + int[] cur = q.poll(); + + for(int d=0; d<4; d++) { + int nx = cur[0] + dx[d]; + int ny = cur[1] + dy[d]; + if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue; + if(foodBoard[nx][ny] != food) continue; + if(checked[nx][ny]) continue; + + q.offer(new int[] {nx, ny}); + checked[nx][ny] = true; + groupSize++; + + /** + * 그룹의 대표자 구하기 + */ + if(master.believe < believeBoard[nx][ny]) { + master = new Master(nx, ny, food, believeBoard[nx][ny]); + } else if(master.believe == believeBoard[nx][ny] && + (master.x > nx || (master.x == nx && master.y > ny))) { + master = new Master(nx, ny, food, believeBoard[nx][ny]); + } + } + } + + believeBoard[master.x][master.y] += groupSize; + master.believe = believeBoard[master.x][master.y]; + return master; + } + static void evening() { + boolean[][] defense = new boolean[n][n]; + while(!pq.isEmpty()) { + Master master = pq.poll(); + if(defense[master.x][master.y]) continue; // 방어 상태라면 전파를 하지 않음 + + // 신앙심을 1만 남기고 간절함으로 변경 + int begging = master.believe - 1; + int dir = master.believe%4; + believeBoard[master.x][master.y] = 1; + + spread(master, begging, dir, defense); + } + } + static void spread(Master master, int begging, int dir, boolean[][] defense) { + Queue q = new ArrayDeque<>(); + + q.offer(new int[] {master.x, master.y}); + while(!q.isEmpty() && begging > 0) { + int[] cur = q.poll(); + + int nx = cur[0] + dx[dir]; + int ny = cur[1] + dy[dir]; + if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue; + if(foodBoard[nx][ny] != master.food) { // 음식이 다를때만 전파, 같다면 패스하고 다음칸 + int targetBelieve = believeBoard[nx][ny]; + + if (begging > targetBelieve) { // 강한 전파 성공 + foodBoard[nx][ny] = master.food; + believeBoard[nx][ny]++; + begging -= (targetBelieve + 1); + + } else if (begging <= targetBelieve) { // 약한 전파 성공 + foodBoard[nx][ny] |= master.food; + believeBoard[nx][ny] += begging; + begging = 0; + } + defense[nx][ny] = true; + } + q.offer(new int[] {nx, ny}); + } + } + static void finishDay() { + int[] answer = new int[(1<<3)]; + for(int x=0; x 0) { + st = new StringTokenizer(br.readLine().trim()); + int cmd = Integer.parseInt(st.nextToken()); + + if (cmd == SET) set(); + else if (cmd == MOVE) { + int result = move(); + sb.append(result).append('\n'); + } + else if (cmd == CHANGE) { + int result = change(); + sb.append(result).append('\n'); + } else if (cmd == MOD) { + int result = mod(); + sb.append(result).append('\n'); + } else if (cmd == GIFT_QUERY) { + int result = giftQuery(); + sb.append(result).append('\n'); + } else if (cmd == BELT_QUERY) { + int result = beltQuery(); + sb.append(result).append('\n'); + } +// printBelt(); +// System.out.println("_________________________"); + } + } + + /** + * n 개의 벨트 설치 + * m 개의 물건 -> m 개의 선물 위치가 공백을 사이에 두고 주어진다. + */ + static class Node { + int id; + Node prev, next; + + Node(int id) { + this.id = id; + } + + void init() { + prev = null; + next = null; + } + } + + static class Belt { + Node head; + Node tail; + int size; + + Belt() { + this.head = null; + this.tail = null; + this.size = 0; + } + + void addLast(Node node) { + if (head == null) { + head = node; + } else { + tail.next = node; + node.prev = tail; + } + tail = node; + size++; + } + + void addFirst(Node node) { + if(head == null) { + tail = node; + } else { + head.prev = node; + node.next = head; + } + head = node; + size++; + } + + Node pollFirst() { + if(size == 0) return null; + + Node node = head; + if(size == 1) { + head = null; + tail = null; + } else { + Node next = node.next; + next.prev = null; + head = next; + } + + size--; + node.init(); + return node; + } + } + + static int n, m; + static Node[] nodes; + static Belt[] belts; + static void set() { + n = Integer.parseInt(st.nextToken()); + m = Integer.parseInt(st.nextToken()); + + belts = new Belt[n + 1]; + nodes = new Node[m + 1]; + + // 노드 생성 + for (int i = 1; i < m + 1; i++) nodes[i] = new Node(i); + // 벨트 생성 + for (int i = 1; i < n + 1; i++) belts[i] = new Belt(); + + for (int i = 1; i < m + 1; i++) { + int bId = Integer.parseInt(st.nextToken()); + Node node = nodes[i]; + Belt belt = belts[bId]; + belt.addLast(node); + } + } + + /** + * a 벨트에서 b 벨트로 옮긴다. + * + * a 벨트의 tail 을 b 벨트의 head 와 연결 + * a 벨트의 head 를 b head 로 변경 + */ + static int move() { + int a = Integer.parseInt(st.nextToken()); + int b = Integer.parseInt(st.nextToken()); + + Belt aBelt = belts[a]; + Belt bBelt = belts[b]; + + if(aBelt.size == 0) return bBelt.size; + + Node aHead = aBelt.head; + Node aTail = aBelt.tail; + // Belt b가 비어있는 경우 -> head, tail 통으로 교체 + if(bBelt.size == 0) { + bBelt.head = aHead; + bBelt.tail = aTail; + } else { // 값이 있는 경우 bHead 와 aTail 연결 + bBelt.head.prev = aTail; + aTail.next = bBelt.head; + bBelt.head = aHead; + } + aBelt.head = aBelt.tail = null; + bBelt.size += aBelt.size; + aBelt.size = 0; + + return bBelt.size; + } + + /** + * a, b 벨트의 맨 앞에 있는 물건을 교체한다. + * b 벨트의 물건 개수를 출력한다. + * + * 둘 중 선물이 존재하지 않는다면 옮기기만 한다. (교체 X) + */ + static int change() { + int a = Integer.parseInt(st.nextToken()); + int b = Integer.parseInt(st.nextToken()); + + Belt aBelt = belts[a]; + Belt bBelt = belts[b]; + + Node aFirst = aBelt.pollFirst(); + Node bFirst = bBelt.pollFirst(); + + if(aFirst != null) bBelt.addFirst(aFirst); + if(bFirst != null) aBelt.addFirst(bFirst); + + return bBelt.size; + } + /** + * a -> b 로 선물을 절반 옮긴다. + * 만약 a 개수가 1개인 경우는 옮기지 않는다. + * 옮긴 뒤 b 벨트에 있는 개수를 출력한다. + */ + static int mod() { + int a = Integer.parseInt(st.nextToken()); + int b = Integer.parseInt(st.nextToken()); + + Belt aBelt = belts[a]; + Belt bBelt = belts[b]; + + if(aBelt.size <= 1) return bBelt.size; + + int size = aBelt.size; + + Node first = aBelt.head; + Node last = aBelt.head; + for(int i=1; i
0) { + st = new StringTokenizer(br.readLine().trim()); + int cmd = Integer.parseInt(st.nextToken()); + + if(cmd == SET) { set(); } + else if(cmd == POLL) { + long result = poll(); + sb.append(result).append('\n'); + } + else if(cmd == DEL) { + int result = del(); + sb.append(result).append('\n'); + } + else if(cmd == FIND) { + int result = find(); + sb.append(result).append('\n'); + } + else if(cmd == BROKEN) { + int result = broken(); + sb.append(result).append('\n'); + } + printBelt(); + } + } + static class Node { + int id; + int w; + Node prev; + Node next; + + Node(int id, int w) { + this.id = id; + this.w = w; + this.prev = null; + this.next= null; + } + + void init() { + this.prev = null; + this.next= null; + } + } + static class Belt { + Node head; + Node tail; + int size; + boolean broken; + + Belt() { + this.head = null; + this.tail = null; + this.size = 0; + this.broken = false; + } + /** + * 벨트의 뒷쪽에 물건을 추가하는 경우 + * head 가 null -> 벨트에 물건이 없음 + */ + void addLast(Node node) { + if(head == null) { + head = node; + } else { + tail.next = node; + node.prev = tail; + } + tail = node; + size++; + } + void addFirst(Node node) { + if(head == null) { + tail = node; + } else { + head.prev = node; + node.next = head; + } + head = node; + size++; + } + /** + * 벨트의 맨 앞 원소를 반환 + * - 벨트가 비어있는 경우 + * - 벨트에 하나의 워소만 있는 경우 + * - 여러 원소가 있는 경우 + */ + Node pollFirst() { + if(head == null) return null; + Node node = head; + if(head.next == null) { + head = null; + tail = null; + } else { + Node nextHead = head.next; + nextHead.prev = null; + head = nextHead; + } + node.init(); + size--; + return node; + } + Node pollLast() { + if(head == null) return null; + Node node = tail; + if(tail.prev == null) { + head = null; + tail = null; + } else { + Node newTail = tail.prev; + newTail.next = null; + tail = newTail; + } + node.init(); + size--; + return node; + } + void removeNode(Node node) { + if(node == head) pollFirst(); + else if(node == tail) pollLast(); + else { + if(node.prev != null) node.prev.next = node.next; + if(node.next != null) node.next.prev = node.prev; + + node.init(); + size--; + } + } + } + static int n, m; + static Node[] nodes; + static Map idToNode; + static Map idToId; + static Belt[] belts; + static void set() { + n = Integer.parseInt(st.nextToken()); // 선물의 개수 + m = Integer.parseInt(st.nextToken()); // 벨트의 개수 + + int[] ids = new int[n]; + int[] ws = new int[n]; + for(int i=0; i (); + idToId = new HashMap<>(); + for(int i=0; i 0) { + Node node = b.pollFirst(); + target.addLast(node); + idToId.put(node.id, nb); + } + break; + } + + return bId + 1; + } + //------------------------------ + static void printBelt() { + for(int i=0; i 0) { + st = new StringTokenizer(br.readLine().trim()); + int cmd = Integer.parseInt(st.nextToken()); + + if(cmd == SET) { set(); } + else if(cmd == ADD) { add(); } + else if(cmd == DEL) { del(); } + else if(cmd == QUERY) { sb.append(query()).append('\n'); } + } + } + /** + * [마을 건설] + * 여왕 개미 집을 x = 0 + * N 개의 집 건설 ( 1 ~ N ) + * i 번째 집 위치는 x[i] + */ + static class Home { + int x; + boolean del; + + Home(int x) { + this.x = x; + this.del = false; + } + } + static int n; + static List homes; + static void set() { + homes = new ArrayList<>(); + + n = Integer.parseInt(st.nextToken()); + // 1. 여왕 개미 + homes.add(new Home(0)); + for(int i=0; i 이제까지 건설된 모든 집의 좌표보다 큰 값으로 주어짐 + */ + static void add() { + int x = Integer.parseInt(st.nextToken()); + homes.add(new Home(x)); + } + /** + * [개미집 철거] - 최대 10000번 + * q 번 개미집을 철거한다. + * 유효하지 않은 명령은 들어오지 않는다. + */ + static void del() { + int id = Integer.parseInt(st.nextToken()); + Home home = homes.get(id); + home.del = true; + } + /** + * [개미집 정찰] - 최대 100 번 + * r 마리의 개미가 정찰을 간다. + * 서로 다른 개미집을 선택한다. + * 1초에 1만큼 이동한다. + * 시간이 최소가 되도록한다. + */ + static int query() { + int limit = Integer.parseInt(st.nextToken()); + int l = 0, r = homes.get(homes.size()-1).x; + int min = Integer.MAX_VALUE; + while(l <= r) { + int mid = l + (r - l)/2; + if(isPossible(mid, limit)) { + min = Math.min(min, mid); + r = mid - 1; + } else { + l = mid + 1; + } + } + return min; + } + static boolean isPossible(int time, int limit) { + int lastLoc = -Integer.MAX_VALUE; + int ant = 0; + for(int i=1; i time) { + ant++; + lastLoc = home.x; + } + } + return ant <= limit; + } +} diff --git "a/java/src/mar/week3/codetree/\354\275\224\353\223\234\355\212\270\353\246\254\353\271\265_\353\260\225\354\236\254\355\231\230.java" "b/java/src/mar/week3/codetree/\354\275\224\353\223\234\355\212\270\353\246\254\353\271\265_\353\260\225\354\236\254\355\231\230.java" new file mode 100644 index 0000000..01d79c3 --- /dev/null +++ "b/java/src/mar/week3/codetree/\354\275\224\353\223\234\355\212\270\353\246\254\353\271\265_\353\260\225\354\236\254\355\231\230.java" @@ -0,0 +1,204 @@ +package mar.week3.codetree; + +import java.util.*; +import java.io.*; + +public class 코드트리빵_박재환 { + static BufferedReader br; + public static void main(String[] args) throws IOException { + br = new BufferedReader(new InputStreamReader(System.in)); + init(); + br.close(); + } + /** + * m 명의 사람 + * - 1번 사람은 1분, 2번 사람은 2분, ... m번 사람은 m분에 출발 + * + * 출발 시간 전에는 격자 밖에 있다. + * -> 목표로 하는 편의점은 모두 다르다. + * + * [이동 방법] + * 1. 본인이 가고싶은 편의점 방향을 향해 1칸 이동 (최단 거리로 움직인다.) + * - 여러개인 경우 상 좌 우 하 순으로 움직인다. + * 2. 편의점에 도착한다면 멈춘다. 다른 사람들은 이때부터 해당 칸을 지나갈 수 없다. + * 3. 현재 시간이 t분일 때, t <= m 만족 시, t번 사람은 자신이 가고싶은 편의점과 가장 가까운 베이스 캠프 이동 + * 여러개라면 행 열 작은 순 (이동 시간 소요 X) + * 다른 사람이 못지나감 + */ + static class Store { + int x, y; + + Store(int x, int y) { + this.x = x; + this.y = y; + } + } + static StringTokenizer st; + static int n, m; + static int[][] board; + static Store[] stores; + static void init() throws IOException { + st = new StringTokenizer(br.readLine().trim()); + n = Integer.parseInt(st.nextToken()); + m = Integer.parseInt(st.nextToken()); + + board = new int[n][n]; + for(int x=0; x persons; + static boolean[][] blocked; + static List reservationBlock; + static int arrived; + static void solution() { + arrived = 0; + persons = new ArrayDeque (); + reservationBlock = new ArrayList (); + blocked = new boolean[n][n]; + + int time = 0; + while(arrived < m) { + time++; + movePerson(); + processReservation(); + reservationBlock.clear(); + if(time <= m) addPerson(time); + processReservation(); + reservationBlock.clear(); + } + System.out.println(time); + } + static final int[] dx = {-1,0,0,1}; + static final int[] dy = {0,-1,1,0}; + static void movePerson() { + if(persons.isEmpty()) return; + + // 움직일 수 있는 사람이 있다면 + // BFS 로 돌려도 되는지 모르겠음 + Queue temp = new ArrayDeque (); + while(!persons.isEmpty()) { + int[] person = persons.poll(); + int id = person[0]; + int x = person[1]; + int y = person[2]; + int[] next = findShortestRoute(id, x, y); + // 위치 이동 + person[1] = next[0]; + person[2] = next[1]; + + if(stores[id].x == person[1] && stores[id].y == person[2]) { // 가게에 도착 + reservationBlock.add(new int[] {person[1], person[2]}); + arrived++; + continue; + } + temp.offer(person); + } + + persons = temp; + } + static class Node { + int x, y; + Node prev; + + Node(int x, int y, Node prev) { + this.x = x; + this.y = y; + this.prev = prev; + } + } + static int[] findShortestRoute(int id, int x, int y) { + Queue q = new ArrayDeque<>(); + boolean[][] visited = new boolean[n][n]; + + q.offer(new Node(x, y, null)); + visited[x][y] = true; + + Store s = stores[id]; // 선호하는 편의점 + while(!q.isEmpty()) { + Node cur = q.poll(); + if(cur.x == s.x && cur.y == s.y) { + return recoverRoute(cur); + } + + for(int dir=0; dir<4; dir++) { + int nx = cur.x + dx[dir]; + int ny = cur.y + dy[dir]; + if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue; + if(visited[nx][ny] || blocked[nx][ny]) continue; + + visited[nx][ny] = true; + q.offer(new Node(nx, ny, cur)); + } + } + return null; + } + static int[] recoverRoute(Node cur) { + while(cur.prev != null && cur.prev.prev != null) { + cur = cur.prev; + } + return new int[] {cur.x, cur.y}; + } + static void addPerson(int time) { + Queue q = new ArrayDeque<>(); + boolean[][] visited = new boolean[n][n]; + Store s = stores[time]; + + q.offer(new int[] {s.x, s.y, 0}); + visited[s.x][s.y] = true; + + int bx = 20, by = 20, bd = 500; + while(!q.isEmpty()) { + int[] cur = q.poll(); + int x = cur[0]; + int y = cur[1]; + int d = cur[2]; + + if(board[x][y] == 1) { + if(bd > d) { + bx = x; + by = y; + bd = d; + } else if(bd == d && (bx > x || (bx == x && by > y))) { + bx = x; + by = y; + } + } + + if(bd < d) continue; + for(int dir=0; dir<4; dir++) { + int nx = x + dx[dir]; + int ny = y + dy[dir]; + if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue; + if(visited[nx][ny] || blocked[nx][ny]) continue; + + visited[nx][ny] = true; + q.offer(new int[] {nx, ny, d+1}); + } + } + persons.offer(new int[] {time, bx, by}); + reservationBlock.add(new int[] {bx, by}); + } + static void processReservation() { + for(int[] a : reservationBlock) { + int x = a[0]; + int y = a[1]; + blocked[x][y] = true; + } + } +} diff --git "a/java/src/mar/week3/codetree/\355\206\240\353\201\274\354\231\200\352\262\275\354\243\274_\353\260\225\354\236\254\355\231\230.java" "b/java/src/mar/week3/codetree/\355\206\240\353\201\274\354\231\200\352\262\275\354\243\274_\353\260\225\354\236\254\355\231\230.java" new file mode 100644 index 0000000..bbe76fc --- /dev/null +++ "b/java/src/mar/week3/codetree/\355\206\240\353\201\274\354\231\200\352\262\275\354\243\274_\353\260\225\354\236\254\355\231\230.java" @@ -0,0 +1,176 @@ +package mar.week3.codetree; + +import java.util.*; +import java.io.*; + +public class 토끼와경주_박재환 { + static BufferedReader br; + static StringBuilder sb; + public static void main(String[] args) throws IOException { + br = new BufferedReader(new InputStreamReader(System.in)); + sb = new StringBuilder(); + init(); + br.close(); + System.out.println(sb); + } + static final int READY = 100; + static final int START = 200; + static final int CHANGE = 300; + static final int PICK = 400; + + static StringTokenizer st; + static void init() throws IOException { + int q = Integer.parseInt(br.readLine().trim()); + while(q-- > 0) { + st = new StringTokenizer(br.readLine().trim()); + int cmd = Integer.parseInt(st.nextToken()); + + if(cmd == READY) { ready(); } + else if(cmd == START) { start(); } + else if(cmd == CHANGE) { change(); } + else if(cmd == PICK) { sb.append(pick()); } + } + } + static class Rabbit { + int id; // 고유 id + int x, y; // 현 위치 + int d; // 이동 거리 + int jump; + int score; + + Rabbit(int id, int x, int y, int d, int jump, int score) { + this.id = id; + this.x = x; + this.y = y; + this.d = d; + this.jump = jump; + this.score = score; + } + } + static int n, m, p; + static Map rabbits; + static PriorityQueue rabbitPq; + static long totalScore; + static void ready() { + totalScore = 0; + + n = Integer.parseInt(st.nextToken()); + m = Integer.parseInt(st.nextToken()); + p = Integer.parseInt(st.nextToken()); + + rabbits = new HashMap<>(); + rabbitPq = new PriorityQueue<>((a, b) -> { // 경주 진행 우선순위 + if(a.jump != b.jump) return Integer.compare(a.jump, b.jump); + int aSum = a.x + a.y; + int bSum = b.x + b.y; + if(aSum != bSum) return Integer.compare(aSum, bSum); + if(a.x != b.x) return Integer.compare(a.x, b.x); + if(a.y != b.y) return Integer.compare(a.y, b.y); + return Integer.compare(a.id, b.id); + }); + + for(int i=0; i set = new HashSet<>(); + while(k-- > 0) { + int[][] next = new int[4][3]; + Rabbit rabbit = rabbitPq.poll(); + // 현재 토끼가 이동했을 때 4가지 방향의 좌표를 각각 구함 + int x = rabbit.x; + int y = rabbit.y; + + int upX = move(x, -rabbit.d, n); + int upY = y; + next[0] = new int[]{upX, upY, upX + upY}; + + int bottomX = move(x, rabbit.d, n); + int bottomY = y; + next[1] = new int[]{bottomX, bottomY, bottomX + bottomY}; + + int leftX = x; + int leftY = move(y, -rabbit.d, m); + next[2] = new int[]{leftX, leftY, leftX + leftY}; + + int rightX = x; + int rightY = move(y, rabbit.d, m); + next[3] = new int[]{rightX, rightY, rightX + rightY}; + + Arrays.sort(next, (a, b) -> { + if(a[2] != b[2]) return Integer.compare(b[2], a[2]); + if(a[0] != b[0]) return Integer.compare(b[0], a[0]); + return Integer.compare(b[1], a[1]); + }); + + rabbit.x = next[0][0]; + rabbit.y = next[0][1]; + rabbit.jump++; + + // 다른 토끼들의 점수 업데이트 -> 오래걸릴듯 + // => 반대로 생각 : 이동한 토끼만 점수를 잃는다. + rabbit.score -= (rabbit.x + rabbit.y); + totalScore += rabbit.x + rabbit.y; + rabbitPq.offer(rabbit); + set.add(rabbit.id); + } + + Rabbit r = null; + for(int i : set) { + Rabbit rabbit = rabbits.get(i); + if(r == null) { + r = rabbit; + } else { + int sum1 = r.x + r.y; + int sum2 = rabbit.x + rabbit.y; + + if(sum1 < sum2 || + (sum1 == sum2 && r.x < rabbit.x) || + (sum1 == sum2 && r.x == rabbit.x && r.y < rabbit.y) || + (sum1 == sum2 && r.x == rabbit.x && r.y == rabbit.y && r.id < rabbit.id)) { + r = rabbit; + } + } + } + r.score += s; + } + + static int move(int pos, int dist, int limit) { + int cycle = 2 * (limit - 1); // 사이클 주기 + dist %= cycle; + + int next = pos + dist; + + while (next < 1 || next > limit) { // 격자밖이라면 반사처리 + if (next < 1) next = 2 - next; + else next = 2 * limit - next; + } + + return next; + } + + static void change() { + int id = Integer.parseInt(st.nextToken()); + int l = Integer.parseInt(st.nextToken()); + + Rabbit r = rabbits.get(id); + r.d *= l; + } + + static long pick() { + int max = -1; + for(Rabbit r : rabbits.values()) { + max = Math.max(r.score, max); + } + return max + totalScore; + } +} diff --git "a/java/src/mar/week3/codetree/\355\217\254\355\203\221\353\266\200\354\210\230\352\270\260_\353\260\225\354\236\254\355\231\230.java" "b/java/src/mar/week3/codetree/\355\217\254\355\203\221\353\266\200\354\210\230\352\270\260_\353\260\225\354\236\254\355\231\230.java" new file mode 100644 index 0000000..4035576 --- /dev/null +++ "b/java/src/mar/week3/codetree/\355\217\254\355\203\221\353\266\200\354\210\230\352\270\260_\353\260\225\354\236\254\355\231\230.java" @@ -0,0 +1,226 @@ +package mar.week3.codetree; + +import java.util.*; +import java.io.*; + +public class 포탑부수기_박재환 { + static BufferedReader br; + public static void main(String[] args) throws IOException { + br = new BufferedReader(new InputStreamReader(System.in)); + init(); + br.close(); + } + /** + * N x M + * 모든 위치에 포탑이 있음 + * 공격력이 0 이하가 된다면 부셔짐 + */ + static StringTokenizer st; + static int n, m, k; + static int[][] board; + static int[][] lastAttack; + static void init() throws IOException { + st = new StringTokenizer(br.readLine().trim()); + n = Integer.parseInt(st.nextToken()); + m = Integer.parseInt(st.nextToken()); + k = Integer.parseInt(st.nextToken()); + + board = new int[n][m]; + lastAttack = new int[n][m]; + for(int x=0; x
q = new ArrayDeque<>(); + boolean[][] visited = new boolean[n][m]; + + q.offer(new Node(attacker.x, attacker.y, null)); + visited[attacker.x][attacker.y] = true; + + while(!q.isEmpty()) { + Node cur = q.poll(); + if(cur.x == target.x && cur.y == target.y) { + recoverRoute(cur, attacker, target); + return true; + } + + for(int dir=0; dir<4; dir++) { + int nx = cur.x + dx[dir]; + int ny = cur.y + dy[dir]; + if(nx < 0 || ny < 0 || nx >=n || ny >= m) { + /** + * 격자 밖으로 나가면 반대편 방향으로 나온다. + */ + nx = (nx + n) % n; + ny = (ny + m) % m; + } + if(board[nx][ny] == 0) continue; + if(visited[nx][ny]) continue; + + visited[nx][ny] = true; + q.offer(new Node(nx, ny, cur)); + } + } + return false; + } + static void attackByCanon(Canon attacker, Canon target) { + board[target.x][target.y] = Math.max(board[target.x][target.y] - attacker.power, 0); + involved[target.x][target.y] = true; + + for(int dir = 0; dir < 8; dir++) { + int nx = target.x + dx[dir]; + int ny = target.y + dy[dir]; + if(nx < 0 || ny < 0 || nx >=n || ny >= m) { + /** + * 격자 밖으로 나가면 반대편 방향으로 나온다. + */ + nx = (nx + n) % n; + ny = (ny + m) % m; + } + if(board[nx][ny] == 0) continue; + if(nx == attacker.x && ny == attacker.y) continue; + board[nx][ny] = Math.max(board[nx][ny] - (attacker.power / 2), 0); + involved[nx][ny] = true; + } + } + static void recoverRoute(Node cur, Canon attacker, Canon target) { + board[target.x][target.y] = Math.max(board[target.x][target.y] - attacker.power, 0); + involved[target.x][target.y] = true; + + cur = cur.prev; // target 바로 이전부터 시작 + while(cur != null && !(cur.x == attacker.x && cur.y == attacker.y)) { + board[cur.x][cur.y] = Math.max(board[cur.x][cur.y] - (attacker.power / 2), 0); + involved[cur.x][cur.y] = true; + cur = cur.prev; + } + } + // ================================================= + static boolean isBetterAttacker(Canon a, Canon b) { + if(a.power != b.power) return a.power < b.power; + if(a.lastAttack != b.lastAttack) return a.lastAttack > b.lastAttack; + int aSum = a.x + a.y; + int bSum = b.x + b.y; + if(aSum != bSum) return aSum > bSum; + return a.y > b.y; + } + static boolean isBetterTarget(Canon a, Canon b) { + if(a.power != b.power) return a.power > b.power; + if(a.lastAttack != b.lastAttack) return a.lastAttack < b.lastAttack; + int aSum = a.x + a.y; + int bSum = b.x + b.y; + if(aSum != bSum) return aSum < bSum; + return a.y < b.y; + } + static int countAlive() { + int cnt = 0; + for (int x = 0; x < n; x++) { + for (int y = 0; y < m; y++) { + if (board[x][y] > 0) cnt++; + } + } + return cnt; + } + static int findMaxPower() { + int max = 0; + for(int x = 0; x < n; x++) { + for(int y = 0; y < m; y++) { + max = Math.max(max, board[x][y]); + } + } + return max; + } +} diff --git "a/java/src/mar/week3/codetree/\355\225\264\354\202\260\353\254\274\354\261\204\354\267\250_\353\260\225\354\236\254\355\231\230.java" "b/java/src/mar/week3/codetree/\355\225\264\354\202\260\353\254\274\354\261\204\354\267\250_\353\260\225\354\236\254\355\231\230.java" new file mode 100644 index 0000000..84eeb78 --- /dev/null +++ "b/java/src/mar/week3/codetree/\355\225\264\354\202\260\353\254\274\354\261\204\354\267\250_\353\260\225\354\236\254\355\231\230.java" @@ -0,0 +1,167 @@ +package mar.week3.codetree; + +import java.util.*; +import java.io.*; + +public class 해산물채취_박재환 { + static BufferedReader br; + static StringBuilder sb; + + public static void main(String[] args) throws IOException { + br = new BufferedReader(new InputStreamReader(System.in)); + sb = new StringBuilder(); + init(); + br.close(); + System.out.println(sb); + } + + static StringTokenizer st; + static int n, m; + static int[][] board; + + static void init() throws IOException { + st = new StringTokenizer(br.readLine().trim()); + n = Integer.parseInt(st.nextToken()); + m = Integer.parseInt(st.nextToken()); + + board = new int[n][m]; + for (int x = 0; x < n; x++) { + st = new StringTokenizer(br.readLine().trim()); + for (int y = 0; y < m; y++) board[x][y] = Integer.parseInt(st.nextToken()); + } + solution(); + } + + /** + * N x M 격자 + * - 각 칸에는 채취할 수 있는 해산물의 양 + * + * 총 Q명의 사람 ( 1 ~ Q ) 순서대로 해산물을 채취하러 들어감 + * i 번재 사람은 멘헤튼 거리 d 이하의 격자 중 해산물이 가장 많은 격자로 이동 + * - 여러개인 경우, 행 - 열 작은 순 + * - 해당 격자에 해산물이 K만큼 있다면 K/2만큼 남기고 채취 + *
+ * i번째 사람이 채취를 마친 후 해류 발생 -> 일부 영역 해산물 위치 바뀜 + * - 시계 방향 / 반시계 방향 + */ + static void solution() throws IOException { + int q = Integer.parseInt(br.readLine().trim()); + for (int i = 1; i <= 2 * q; i++) { + st = new StringTokenizer(br.readLine().trim()); + if (i % 2 == 0) { // 해류 + int x1 = Integer.parseInt(st.nextToken()) - 1; + int y1 = Integer.parseInt(st.nextToken()) - 1; + int x2 = Integer.parseInt(st.nextToken()) - 1; + int y2 = Integer.parseInt(st.nextToken()) - 1; + int a = Integer.parseInt(st.nextToken()); + + rotate(x1, y1, x2, y2, a); + } else { // 채취 + int x = Integer.parseInt(st.nextToken()) - 1; + int y = Integer.parseInt(st.nextToken()) - 1; + int d = Integer.parseInt(st.nextToken()); + int takeV = take(x, y, d); + sb.append(takeV).append('\n'); + } + } + } + + static int take(int x, int y, int d) { + int bestV = board[x][y]; + int bestX = x; + int bestY = y; + + for (int i = Math.max(0, x - d); i < Math.min(n, x + d + 1); i++) { + for (int j = Math.max(0, y - d); j < Math.min(m, y + d + 1); j++) { + if (getDist(x, y, i, j) > d) continue; + + if (bestV < board[i][j]) { + bestV = board[i][j]; + bestX = i; + bestY = j; + } else if (bestV == board[i][j]) { + if (bestX > i || (bestX == i && bestY > j)) { + bestX = i; + bestY = j; + } + } + } + } + + board[bestX][bestY] = bestV / 2; + return bestV - board[bestX][bestY]; + } + + static void rotate(int x1, int y1, int x2, int y2, int a) { + int h = x2 - x1 + 1; + int w = y2 - y1 + 1; + int len = 2 * (h + w) - 4; + + int id = 0; + int[] origin = new int[len]; + // 위 + for (int y = y1; y <= y2; y++) origin[id++] = board[x1][y]; + // 오른쪽 + for (int x = x1 + 1; x <= x2; x++) origin[id++] = board[x][y2]; + // 아래 + for (int y = y2 - 1; y >= y1; y--) origin[id++] = board[x2][y]; + // 왼쪽 + for (int x = x2 - 1; x > x1; x--) origin[id++] = board[x][y1]; + + a %= len; + if(a < 0) a += len; + int start = (len-a)%len; + id = 0; + // 위 + for (int y = y1; y <= y2; y++) board[x1][y] = origin[(start + id++)%len]; + // 오른쪽 + for (int x = x1 + 1; x <= x2; x++) board[x][y2] = origin[(start + id++)%len]; + // 아래 + for (int y = y2 - 1; y >= y1; y--) board[x2][y] = origin[(start + id++)%len]; + // 왼쪽 + for (int x = x2 - 1; x > x1; x--) board[x][y1] = origin[(start + id++)%len]; + } + + //---------------------------------------------------------------------- + static int getDist(int x1, int y1, int x2, int y2) { + return Math.abs(x1 - x2) + Math.abs(y1 - y2); + } +} + +/* +[input] +4 5 +2 3 9 7 8 +4 2 4 5 4 +7 1 6 4 3 +1 3 11 3 11 +2 +2 2 1 +2 2 4 5 -2 +3 3 2 +1 1 3 3 1 + +[output] +2 +5 +---- +[input] +5 7 +8 10 27 34 40 7 8 +25 10 25 10 39 43 2 +11 25 17 51 51 49 38 +13 12 14 15 48 35 99 +77 68 2 3 40 37 56 +3 +3 5 2 +2 1 4 4 -3 +3 2 1 +1 1 2 2 1 +1 1 1 +1 1 5 7 100 + +[output] +26 +13 +6 + */ \ No newline at end of file