회사원 Demi는 가끔은 야근을 하는데요, 야근을 하면 야근 피로도가 쌓입니다. 야근 피로도는 야근을 시작한 시점에서 남은 일의 작업량을 제곱하여 더한 값입니다. Demi는 N시간 동안 야근 피로도를 최소화하도록 일할 겁니다.Demi가 1시간 동안 작업량 1만큼을 처리할 수 있다고 할 때, 퇴근까지 남은 N 시간과 각 일에 대한 작업량 works에 대해 야근 피로도를 최소화한 값을 리턴하는 함수 solution을 완성해주세요.
제한 사항
works는 길이 1 이상, 20,000 이하인 배열입니다.
works의 원소는 50000 이하인 자연수입니다.
n은 1,000,000 이하인 자연수입니다.
입출력 예worksnresult
[4, 3, 3]
4
12
[2, 1, 2]
1
6
[1,1]
3
0
입출력 예 설명
입출력 예 #1 n=4 일 때, 남은 일의 작업량이 [4, 3, 3] 이라면 야근 지수를 최소화하기 위해 4시간동안 일을 한 결과는 [2, 2, 2]입니다. 이 때 야근 지수는 22+ 22+ 22= 12 입니다.
입출력 예 #2 n=1일 때, 남은 일의 작업량이 [2,1,2]라면 야근 지수를 최소화하기 위해 1시간동안 일을 한 결과는 [1,1,2]입니다. 야근지수는 12+ 12+ 22= 6입니다.
입출력 예 #3
남은 작업량이 없으므로 피로도는 0입니다.
📝풀이
우선순위 큐를 이용하여 문제 해결
import java.util.*;
class Solution {
public long solution(int n, int[] works) {
long answer = 0;
PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
for(int i=0; i<works.length; i++){
pq.offer(works[i]);
}
int max;
while(n>0){
if(pq.peek()==0)
return 0;
pq.offer(pq.poll()-1);
n--;
}
while(!pq.isEmpty()){
answer+= Math.pow(pq.poll(), 2);
}
return answer;
}
}
지형은 각 변이 x축, y축과 평행한 직사각형이 겹쳐진 형태로 표현하며, 캐릭터는 이 다각형의 둘레(굵은 선)를 따라서 이동합니다.
만약 직사각형을 겹친 후 다음과 같이 중앙에 빈 공간이 생기는 경우, 다각형의 가장 바깥쪽 테두리가 캐릭터의 이동 경로가 됩니다.
단, 서로 다른 두 직사각형의 x축 좌표 또는 y축 좌표가 같은 경우는 없습니다.
즉, 위 그림처럼 서로 다른 두 직사각형이 꼭짓점에서 만나거나, 변이 겹치는 경우 등은 없습니다.
다음 그림과 같이 지형이 2개 이상으로 분리된 경우도 없습니다.
한 직사각형이 다른 직사각형 안에 완전히 포함되는 경우 또한 없습니다.
지형을 나타내는 직사각형이 담긴 2차원 배열 rectangle, 초기 캐릭터의 위치 characterX, characterY, 아이템의 위치 itemX, itemY가 solution 함수의 매개변수로 주어질 때, 캐릭터가 아이템을 줍기 위해 이동해야 하는 가장 짧은 거리를 return 하도록 solution 함수를 완성해주세요.
제한사항
rectangle의 세로(행) 길이는 1 이상 4 이하입니다.
rectangle의 원소는 각 직사각형의 [좌측 하단 x, 좌측 하단 y, 우측 상단 x, 우측 상단 y] 좌표 형태입니다.
직사각형을 나타내는 모든 좌표값은 1 이상 50 이하인 자연수입니다.
서로 다른 두 직사각형의 x축 좌표, 혹은 y축 좌표가 같은 경우는 없습니다.
문제에 주어진 조건에 맞는 직사각형만 입력으로 주어집니다.
charcterX, charcterY는 1 이상 50 이하인 자연수입니다.
지형을 나타내는 다각형 테두리 위의 한 점이 주어집니다.
itemX, itemY는 1 이상 50 이하인 자연수입니다.
지형을 나타내는 다각형 테두리 위의 한 점이 주어집니다.
캐릭터와 아이템의 처음 위치가 같은 경우는 없습니다.
전체 배점의 50%는 직사각형이 1개인 경우입니다.
전체 배점의 25%는 직사각형이 2개인 경우입니다.
전체 배점의 25%는 직사각형이 3개 또는 4개인 경우입니다.
입출력 예
rectangle
characterX
characterY
itemX
itemY
result
[[1,1,7,4],[3,2,5,5],[4,3,6,9],[2,6,8,8]]
1
3
7
8
17
[[1,1,8,4],[2,2,4,9],[3,6,9,8],[6,3,7,7]]
9
7
6
1
11
[[1,1,5,7]]
1
1
4
7
9
[[2,1,7,5],[6,4,10,10]]
3
1
7
10
15
[[2,2,5,5],[1,3,6,4],[3,1,4,6]]
1
4
6
3
10
입출력 예 설명
입출력 예 1)
캐릭터 위치는 (1, 3)이며, 아이템 위치는 (7, 8)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.
입출력 예 2)
캐릭터 위치는 (9, 7)이며, 아이템 위치는 (6, 1)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.
입출력 예 3)
캐릭터 위치는 (1, 1)이며, 아이템 위치는 (4, 7)입니다. 위 그림과 같이 굵은 선을 따라 이동하는 경로가 가장 짧습니다.
입출력 예 4, 5)
설명 생략
>문제 풀이
길을 찾으려면 도형들의 테두리가 필요합니다.
도형 하나 받고 다음 도형을 받을 텐데, 테두리를 제외하고 내부는 필요가 없습니다.
1) int map[101][101]
- 꺾이는 코너 부분에서 쉽게 계산하기 위해,
입력되는 좌표는 1~50이지만 2배로 확장해서 그려줄 것입니다.
2) 주어진 rectangle[][] 도형 정보에 따라 map에 채워넣습니다.
이처럼 테두리를 표시할 때, 겹쳐서 테두리가 될 수 없는 부분과 진짜 테두리를 구분해줘야합니다.
- 1. 테두리에는 1을 넣어주고, 내부에는 2를 넣어줄 것입니다.
- 2. 다음 그려질 도형이, 앞에 이미 그려진 도형이랑 겹칠 수 있습니다.
- 도형의 내부이면 2를 넣습니다.
- 테두리에는 1을 넣되, 이미 값이 2로 채워져 있는 경우는 2로 남겨둡니다.
(어차피 다른 도형의 내부니까 전체 테두리가 될 수 없음)
3) bfs로 출발점에서 목표 지점까지 양쪽에서 출발합니다.
만든 map이 2배 확장된 공간이기 때문에 좌표도 x2 해서 계산합니다.
4) return answer;
앞서 좌표를 x2해서 계산해주었으므로 정답을 반환할 때는 /2 해야합니다.
>전체 코드
import java.util.Queue;
import java.util.LinkedList;
class Solution {
static int[][] map;
static int answer;
//character->item(목표 포인트)
public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) {
answer=0;
//1) map을 만든다.
map= new int[101][101];
//2) 좌표에 따라 map에 값을 넣을건데, 테두리에만 1을 넣을것이다.(*좌표는 두배로)
for(int i=0; i<rectangle.length; i++){
fill(2*rectangle[i][0], 2*rectangle[i][1], 2*rectangle[i][2], 2*rectangle[i][3]);
}
//3) bfs로 테두리 따라 양쪽으로 가보고 min값 채택
bfs(2*characterX, 2*characterY, 2*itemX, 2*itemY);
return answer/2;
}
//x1,y1,x2,y2 => (x1,y1)~(x2,y1), (x1,y2)~(x2,y2), (x1,y1)~(x1,y2), (x2,y1)~(x2,y2)
//편하게 x2 해준 좌표를 받는다.
public void fill(int x1, int y1, int x2, int y2){
for(int i=x1; i<=x2; i++){
for(int j=y1; j<=y2; j++){
if(map[i][j]==2) continue;
map[i][j]=2;
if(i==x1||i==x2||j==y1||j==y2){
map[i][j]=1;
}
}
}
}//fill
static int[] dx= {-1, 0, 0, 1};
static int[] dy= {0, -1, 1, 0};
public void bfs(int startx, int starty, int itemx, int itemy){
boolean[][] visited= new boolean[101][101];
Queue<Integer> queue= new LinkedList<>();
queue.add(startx);
queue.add(starty);
while(!queue.isEmpty()){
int x= queue.poll();
int y= queue.poll();
for(int i=0; i<4; i++){
int nx= x+dx[i];
int ny= y+dy[i];
if(!check(nx, ny)) continue; //범위 아웃
if(map[nx][ny]!=1||visited[nx][ny]) continue;
//map[nx][ny]==2이고 방문한적없음
map[nx][ny]=map[x][y]+1;
if(nx==itemx&&ny==itemy){ //목표점 도달
answer= (answer==0)? map[nx][ny]:Math.min(answer,map[nx][ny]);
continue;
}
visited[nx][ny]= true;
queue.add(nx);
queue.add(ny);
}
}
}//bfs
public boolean check(int x, int y){
if(x<0||y<0||x>100||y>100) return false;
return true;
}
}
n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있습니다. 당신은 이 전선들 중 하나를 끊어서 현재의 전력망 네트워크를 2개로 분할하려고 합니다. 이때, 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고자 합니다.
송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)를 return 하도록 solution 함수를 완성해주세요.
제한사항
n은 2 이상 100 이하인 자연수입니다.
wires는 길이가 n-1인 정수형 2차원 배열입니다.
wires의 각 원소는 [v1, v2] 2개의 자연수로 이루어져 있으며, 이는 전력망의 v1번 송전탑과 v2번 송전탑이 전선으로 연결되어 있다는 것을 의미합니다.
1 ≤ v1 < v2 ≤ n 입니다.
전력망 네트워크가 하나의 트리 형태가 아닌 경우는 입력으로 주어지지 않습니다.
입출력 예
n
wires
result
9
[[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]]
3
4
[[1,2],[2,3],[3,4]]
0
7
[[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]]
1
입출력 예 설명
입출력 예 1
다음 그림은 주어진 입력을 해결하는 방법 중 하나를 나타낸 것입니다.
4번과 7번을 연결하는 전선을 끊으면 두 전력망은 각 6개와 3개의 송전탑을 가지며, 이보다 더 비슷한 개수로 전력망을 나눌 수 없습니다.
또 다른 방법으로는 3번과 4번을 연결하는 전선을 끊어도 최선의 정답을 도출할 수 있습니다.
입출력 예 2
다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다.
2번과 3번을 연결하는 전선을 끊으면 두 전력망이 모두 2개의 송전탑을 가지게 되며, 이 방법이 최선입니다.
입출력 예 3
다음 그림은 주어진 입력을 해결하는 방법을 나타낸 것입니다.
3번과 7번을 연결하는 전선을 끊으면 두 전력망이 각각 4개와 3개의 송전탑을 가지게 되며, 이 방법이 최선입니다.
>문제 풀이
1. 인접 행렬 또는 인접리스트를 이용해서 그래프를 표현해줍니다.
2. for(반복문) : 선을 하나씩 끊어보며, 나눠진 두 전력망의 송전탑 개수의 차이를 구할 것입니다.
2-1) 선 하나를 끊습니다.
2-2) bfs 를 이용하여 끊어진 선의 두 노드 중 하나를 선택하여 연결된 송전탑의 개수를 구해줍니다.(=cnt)
- 두 전력망은 각각 (cnt) 와 ( n-cnt )개의 송전탑을 가질 것입니다.
- Math.abs(n-2*cnt) : 두 전력망이 가지고 있는 송전탑의 개수의 차
- 최솟값을 answer에 갱신해줍니다.
2-3) 선을 다시 복구시켜줍니다.
>전체 코드
import java.util.LinkedList;
import java.util.Queue;
class Solution {
static int[][] arr;
public int solution(int n, int[][] wires) {
int answer = n;
arr= new int[n+1][n+1];
//1. 인접행렬에 input
for(int i=0; i<wires.length; i++){
arr[wires[i][0]][wires[i][1]]=1;
arr[wires[i][1]][wires[i][0]]=1;
}
//2. 선을 하나씩 끊어보며 순회
int a, b;
for(int i=0; i<wires.length; i++){
a= wires[i][0];
b= wires[i][1];
//선을 하나 끊고
arr[a][b]=0;
arr[b][a]=0;
//bfs
answer= Math.min(answer, bfs(n, a));
//선 다시 복구
arr[a][b]=1;
arr[b][a]=1;
}
return answer;
}
public int bfs(int n, int start){
int[] visit= new int[n+1];
int cnt=1;
Queue<Integer> queue= new LinkedList<>();
queue.offer(start);
while(!queue.isEmpty()){
int point= queue.poll();
visit[point]= 1;
for(int i=1; i<=n; i++){ //point와 연결된 애들 중에 방문한적 없는 노드 전부 큐에 넣기
if(visit[i]==1) continue;
if(arr[point][i]==1) {
queue.offer(i);
cnt++;
}
}
}
return (int)Math.abs(n-2*cnt); //cnt-(n-cnt);
}//bfs
}
사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제일 친한 친구인 비버의 굴로 가능한 빨리 도망가 홍수를 피하려고 한다.
티떱숲의 지도는 R행 C열로 이루어져 있다. 비어있는 곳은 '.'로 표시되어 있고, 물이 차있는 지역은 '*', 돌은 'X'로 표시되어 있다. 비버의 굴은 'D'로, 고슴도치의 위치는 'S'로 나타내어져 있다.
매 분마다 고슴도치는 현재 있는 칸과 인접한 네 칸 중 하나로 이동할 수 있다. (위, 아래, 오른쪽, 왼쪽) 물도 매 분마다 비어있는 칸으로 확장한다. 물이 있는 칸과 인접해있는 비어있는 칸(적어도 한 변을 공유)은 물이 차게 된다. 물과 고슴도치는 돌을 통과할 수 없다. 또, 고슴도치는 물로 차있는 구역으로 이동할 수 없고, 물도 비버의 소굴로 이동할 수 없다.
티떱숲의 지도가 주어졌을 때, 고슴도치가 안전하게 비버의 굴로 이동하기 위해 필요한 최소 시간을 구하는 프로그램을 작성하시오.
고슴도치는 물이 찰 예정인 칸으로 이동할 수 없다. 즉, 다음 시간에 물이 찰 예정인 칸으로 고슴도치는 이동할 수 없다. 이동할 수 있으면 고슴도치가 물에 빠지기 때문이다.
[입력]
첫째 줄에 50보다 작거나 같은 자연수 R과 C가 주어진다.
다음 R개 줄에는 티떱숲의 지도가 주어지며, 문제에서 설명한 문자만 주어진다. 'D'와 'S'는 하나씩만 주어진다.
[출력]
첫째 줄에 고슴도치가 비버의 굴로 이동할 수 있는 가장 빠른 시간을 출력한다. 만약, 안전하게 비버의 굴로 이동할 수 없다면, "KAKTUS"를 출력한다.
[예제]
>문제 풀이
D : 비버 굴
S : 고슴도치 위치
* : 물
. : 빈 곳
X : 돌
char mat[][]에 입력값들을 저장하면서, 물의 위치와 시작 위치를 큐에 담아줍니다.
물의 위치를 먼저 쭉 담고, 시작 위치를 담도록 구현했는데 물 먼저 bfs를 해주고 고슴도치가 움직여야 정답값을 효율적으로 구할 수 있기 때문입니다.
(고슴도치가 움직여도 그 다음에 물에 잠기면 처리가 좀 더 복잡해집니다.)
물이 상하좌우로 확장해나갈 때는 mat범위 내에서 발생하며 값도 *으로 변경해줍니다.
고슴도치는 빈 곳으로만 이동해서 D에 도달해야합니다. 최종적으로 D에 도달했을 때, 몇 분 걸렸는지를 출력해야하는데 dp[][]값에 시작 위치부터 카운트해서 최단거리로 D에 도달하는 시간을 구했습니다.
위의 과정을 다 돌렸는데도, D에 도달하지 못했다면 "KAKTUS"를 출력합니다.
저는 처음에 고슴도치가 먼저가고 물이 확장되도록 구현했는데, 이렇게 했더니 queue.size()만큼만 for문을 반복하게 하는데에서 어려움을 겪었습니다.