[문제 설명]

다음과 같은 다각형 모양 지형에서 캐릭터가 아이템을 줍기 위해 이동하려 합니다.

지형은 각 변이 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;
    }
}

https://programmers.co.kr/learn/courses/30/lessons/87694

 

코딩테스트 연습 - 11주차_아이템 줍기

[[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 [[2,2,5,5],[1,3,6,4],[3,1,4,6]] 1 4 6 3 10

programmers.co.kr

 

[문제]

XX게임에는 피로도 시스템(0 이상의 정수로 표현합니다)이 있으며, 일정 피로도를 사용해서 던전을 탐험할 수 있습니다. 이때, 각 던전마다 탐험을 시작하기 위해 필요한 "최소 필요 피로도"와 던전 탐험을 마쳤을 때 소모되는 "소모 피로도"가 있습니다. "최소 필요 피로도"는 해당 던전을 탐험하기 위해 가지고 있어야 하는 최소한의 피로도를 나타내며, "소모 피로도"는 던전을 탐험한 후 소모되는 피로도를 나타냅니다. 예를 들어 "최소 필요 피로도"가 80, "소모 피로도"가 20인 던전을 탐험하기 위해서는 유저의 현재 남은 피로도는 80 이상 이어야 하며, 던전을 탐험한 후에는 피로도 20이 소모됩니다.

이 게임에는 하루에 한 번씩 탐험할 수 있는 던전이 여러개 있는데, 한 유저가 오늘 이 던전들을 최대한 많이 탐험하려 합니다. 유저의 현재 피로도 k와 각 던전별 "최소 필요 피로도", "소모 피로도"가 담긴 2차원 배열 dungeons 가 매개변수로 주어질 때, 유저가 탐험할수 있는 최대 던전 수를 return 하도록 solution 함수를 완성해주세요.

제한사항

k는 1 이상 5,000 이하인 자연수입니다.

dungeons의 세로(행) 길이(즉, 던전의 개수)는 1 이상 8 이하입니다.

dungeons의 가로(열) 길이는 2 입니다.

dungeons의 각 행은 각 던전의 ["최소 필요 피로도", "소모 피로도"] 입니다.

"최소 필요 피로도"는 항상 "소모 피로도"보다 크거나 같습니다.

"최소 필요 피로도"와 "소모 피로도"는 1 이상 1,000 이하인 자연수입니다.

서로 다른 던전의 ["최소 필요 피로도", "소모 피로도"]가 서로 같을 수 있습니다.

입출력 예

k dungeons result
80 [[80,20],[50,40],[30,10]] 3

입출력 예 설명

현재 피로도는 80입니다.

만약, 첫 번째 → 두 번째 → 세 번째 던전 순서로 탐험한다면

현재 피로도는 80이며, 첫 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 또한 80이므로, 첫 번째 던전을 탐험할 수 있습니다. 첫 번째 던전의 "소모 피로도"는 20이므로, 던전을 탐험한 후 남은 피로도는 60입니다.

남은 피로도는 60이며, 두 번째 던전을 돌기위해 필요한 "최소 필요 피로도"는 50이므로, 두 번째 던전을 탐험할 수 있습니다. 두 번째 던전의 "소모 피로도"는 40이므로, 던전을 탐험한 후 남은 피로도는 20입니다.

남은 피로도는 20이며, 세 번째 던전을 돌기위해 필요한 "최소 필요 피로도"는 30입니다. 따라서 세 번째 던전은 탐험할 수 없습니다.

만약, 첫 번째 → 세 번째 → 두 번째 던전 순서로 탐험한다면

현재 피로도는 80이며, 첫 번째 던전을 돌기위해 필요한 "최소 필요 피로도" 또한 80이므로, 첫 번째 던전을 탐험할 수 있습니다. 첫 번째 던전의 "소모 피로도"는 20이므로, 던전을 탐험한 후 남은 피로도는 60입니다.

남은 피로도는 60이며, 세 번째 던전을 돌기위해 필요한 "최소 필요 피로도"는 30이므로, 세 번째 던전을 탐험할 수 있습니다. 세 번째 던전의 "소모 피로도"는 10이므로, 던전을 탐험한 후 남은 피로도는 50입니다.

남은 피로도는 50이며, 두 번째 던전을 돌기위해 필요한 "최소 필요 피로도"는 50이므로, 두 번째 던전을 탐험할 수 있습니다. 두 번째 던전의 "소모 피로도"는 40이므로, 던전을 탐험한 후 남은 피로도는 10입니다.

따라서 이 경우 세 던전을 모두 탐험할 수 있으며, 유저가 탐험할 수 있는 최대 던전 수는 3입니다.

 


>문제 풀이

어떤 유저가 던전을 탐험합니다.

int k : 유저에게 남은 피로도

int[][] dungeons : 던전을 탐험하는데 필요한 "최소 필요 피로도"와 "소모 피로도"

주어지는 던전의 세로행은 1이상 8이하입니다.

전체 경우를 따져봐야 4만 정도 밖에 안되고, 특정한 패턴이 안보이기 때문에 완전탐색으로 풀면 됩니다.

 

 

 

>전체 코드

 

class Solution {
    static int answer;
    static boolean[] visited;
    
    public int solution(int k, int[][] dungeons) {
        answer= 0;
        visited= new boolean[dungeons.length];
        
        dfs(k, dungeons, 0, 0);
        
        return answer;
    }
    
    public void dfs(int k, int[][] dungeons, int idx, int cnt){
        if(idx==dungeons.length){
            answer= answer>cnt ? answer:cnt;
            return;
        }
        
        for(int i=0; i<dungeons.length; i++){
            if(dungeons[i][0]>k||visited[i]) continue;
            visited[i]= true;
            dfs(k-dungeons[i][1], dungeons, idx+1, cnt+1);
            visited[i]= false;
        }
        dfs(k, dungeons, idx+1, cnt);
    }//dfs
}

https://programmers.co.kr/learn/courses/30/lessons/87946

 

코딩테스트 연습 - 12주차

XX게임에는 피로도 시스템(0 이상의 정수로 표현합니다)이 있으며, 일정 피로도를 사용해서 던전을 탐험할 수 있습니다. 이때, 각 던전마다 탐험을 시작하기 위해 필요한 "최소 필요 피로도"와 던

programmers.co.kr

 

[문제]

사전에 알파벳 모음 'A', 'E', 'I', 'O', 'U'만을 사용하여 만들 수 있는, 길이 5 이하의 모든 단어가 수록되어 있습니다. 사전에서 첫 번째 단어는 "A"이고, 그다음은 "AA"이며, 마지막 단어는 "UUUUU"입니다.

단어 하나 word가 매개변수로 주어질 때, 이 단어가 사전에서 몇 번째 단어인지 return 하도록 solution 함수를 완성해주세요.

제한사항

word의 길이는 1 이상 5 이하입니다.

word는 알파벳 대문자 'A', 'E', 'I', 'O', 'U'로만 이루어져 있습니다.

입출력 예

word result
"AAAAE" 6
"AAAE" 10
"I" 1563
"EIO" 1189

입출력 예 설명

입출력 예 1

사전에서 첫 번째 단어는 "A"이고, 그다음은 "AA", "AAA", "AAAA", "AAAAA", "AAAAE", ... 와 같습니다. "AAAAE"는 사전에서 6번째 단어입니다.

입출력 예 2

"AAAE"는 "A", "AA", "AAA", "AAAA", "AAAAA", "AAAAE", "AAAAI", "AAAAO", "AAAAU"의 다음인 10번째 단어입니다.

입출력 예 3

"I"는 1563번째 단어입니다.

입출력 예 4

"EIO"는 1189번째 단어입니다.

 


>문제 풀이

'A', 'E', 'I', 'O', 'U' 모음을 이용해서 만들 수 있는 단어를 사전순으로 정렬한 다음, 입력되는 String word의 순서를 int answer에 담아 return 하면 됩니다.

풀이 1)

저는 'A', 'E', 'I', 'O', 'U' 로 만들 수 있는 모든 조합을 list에 넣고 사전순으로 정렬한 다음 indexOf를 이용해서 순서를 찾았습니다.

 


 

모든 경우의 수가 얼마 안된다고 생각해서 간단하게 생각하고 풀었는데, 다 풀고나서 보니 통과는 했는데 시간이 오래 걸렸더라고요. 그래서 다시 생각해보니 경우의 수를 잘못 생각했었습니다.

풀이 2)

총 5+25+125+625+3125= 3905개 인데,

가장 먼저, 각 알파벳으로 시작할 수 있는 단어는 각각 781개

=> a로 시작하는 단어는 781개

그렇다면 e로 시작하는 단어는 앞에 a로 시작하는 단어 뒤에 나올테니까 적어도 781 다음부터 겠죠?

자릿수에 따라 781 / 156 / 31 / 6 / 1 이므로, 주어진 word를 한글자씩 쪼개서 자릿수 별로 answer에 더해주면 됩니다.

그래서 이 원리로 코드를 다시 짜보았습니다.

 

>전체 코드

코드 1)

import java.util.ArrayList;
import java.util.Collections;
class Solution {
    static char[] alphabet= {'A','E','I','O','U'};
    static ArrayList<String> list;
    
    public int solution(String word) {
        list= new ArrayList<>();
        int answer = 0;
        
        combination(0, "");
        Collections.sort(list);
        answer= list.indexOf(word)+1;
        
        return answer;
    }
    
    public void combination(int index, String str){
        if(index>=5) return;
        for(int i=0; i<alphabet.length; i++){
            list.add(str+alphabet[i]);
            combination(index+1, str+alphabet[i]);
        }
    }//comb
}

코드 2)

class Solution {
    
    public int solution(String word) {
        int answer = 0;
        int total= 3905;
        String aeiou="AEIOU";
        
        for(String str: word.split("")){
            //781, 156, 31, 6, 1
            total/= 5;
            answer+= total*aeiou.indexOf(str)+1;
        }
        
        return answer;
    }
}

https://programmers.co.kr/learn/courses/30/lessons/84512

 

코딩테스트 연습 - 5주차_모음사전

사전에 알파벳 모음 'A', 'E', 'I', 'O', 'U'만을 사용하여 만들 수 있는, 길이 5 이하의 모든 단어가 수록되어 있습니다. 사전에서 첫 번째 단어는 "A"이고, 그다음은 "AA"이며, 마지막 단어는 "UUUUU"입니

programmers.co.kr

 

[문제 설명]

Ax + By + C = 0으로 표현할 수 있는 n개의 직선이 주어질 때, 이 직선의 교점 중 정수 좌표에 별을 그리려 합니다.

예를 들어, 다음과 같은 직선 5개를

  • 2x - y + 4 = 0
  • -2x - y + 4 = 0
  • -y + 1 = 0
  • 5x - 8y - 12 = 0
  • 5x + 8y + 12 = 0

좌표 평면 위에 그리면 아래 그림과 같습니다.

이때, 모든 교점의 좌표는 (4, 1), (4, -4), (-4, -4), (-4, 1), (0, 4), (1.5, 1.0), (2.1, -0.19), (0, -1.5), (-2.1, -0.19), (-1.5, 1.0)입니다. 이 중 정수로만 표현되는 좌표는 (4, 1), (4, -4), (-4, -4), (-4, 1), (0, 4)입니다.

만약 정수로 표현되는 교점에 별을 그리면 다음과 같습니다.

위의 그림을 문자열로 나타낼 때, 별이 그려진 부분은 *, 빈 공간(격자선이 교차하는 지점)은 .으로 표현하면 다음과 같습니다.


이때 격자판은 무한히 넓으니 모든 별을 포함하는 최소한의 크기만 나타내면 됩니다.

따라서 정답은


직선
 A, B, C에 대한 정보가 담긴 배열 line이 매개변수로 주어집니다. 이때 모든 별을 포함하는 최소 사각형을 return 하도록 solution 함수를 완성해주세요.입니다.


제한사항

  • line의 세로(행) 길이는 2 이상 1,000 이하인 자연수입니다.
    • line의 가로(열) 길이는 3입니다.
    • line의 각 원소는 [A, B, C] 형태입니다.
    • A, B, C는 -100,000 이상 100,000 이하인 정수입니다.
    • 무수히 많은 교점이 생기는 직선 쌍은 주어지지 않습니다.
    • A = 0이면서 B = 0인 경우는 주어지지 않습니다.
  • 정답은 1,000 * 1,000 크기 이내에서 표현됩니다.
  • 별이 한 개 이상 그려지는 입력만 주어집니다.

입출력 예

lineresult

[[2, -1, 4], [-2, -1, 4], [0, -1, 1], [5, -8, -12], [5, 8, 12]] ["....*....", ".........", ".........", "*.......*", ".........", ".........", ".........", ".........", "*.......*"]
[[0, 1, -1], [1, 0, -1], [1, 0, 1]] ["*.*"]
[[1, -1, 0], [2, -1, 0]] ["*"]
[[1, -1, 0], [2, -1, 0], [4, -1, 0]] ["*"]

입출력 예 설명

입출력 예 #1

문제 예시와 같습니다.

입출력 예 #2

직선 y = 1, x = 1, x = -1는 다음과 같습니다.

(-1, 1), (1, 1) 에서 교점이 발생합니다.

따라서 정답은

"*.*"

입니다.

 

입출력 예 #3

직선 y = x, y = 2x는 다음과 같습니다.

(0, 0) 에서 교점이 발생합니다.

따라서 정답은

"*"

입니다.

 

입출력 예 #4

직선 y = x, y = 2x, y = 4x는 다음과 같습니다.

(0, 0) 에서 교점이 발생합니다.

따라서 정답은

"*"

입니다.


참고 사항

Ax + By + E = 0
Cx + Dy + F = 0
두 직선의 교점이 유일하게 존재할 경우, 그 교점은 다음과 같습니다.

또, AD - BC = 0인 경우 두 직선은 평행 또는 일치합니다.

 


>문제 풀이

* 프로그래머스 위클리 챌린지 10주차 문제입니다.

 

문제에서 두 직선의 교점을 구하는 식을 줬습니다.

x= (BF-ED)/(AD-BC)

y= (EC-AF)/(AD-BC)

쉬운 증명이지만, 문제 풀이 전에 간단히 설명하고 넘어가겠습니다.

① Ax+By+E=0

② Cx+Dy+F=0

-----------------------

① x= -(By+E)/A

② x= -(Dy+F)/C

1, 2번 식을 통해서 (By+E)*C=(Dy+F)*A

(BC-AD)*y = (AF-CE)

y=(AF-CE)/(BC-AD)

같은 방법으로 x를 구할 수 있습니다.


 

자 이제 풀이에 관해,

1) for 문을 돌면서 두 직선들의 교점을 구하고, 구한 교점들을 hashset에 넣어줍니다.

1-1) (AD-BC)==0 이면, 두 직선은 평행하다고 볼 수 있습니다.

(만약, 분자가 0일 경우 두 직선이 겹친다는 소리인데, 문제에서 이런 경우의 입력은 안주어진다고 했으니 신경 안써줘도 됩니다.)

1-2) 두 교점이 정수인지 아닌지 판별하여, 구한 교점 x, y가 모두 정수인 것만 HashSet<Point> 에 넣어줍니다.

1-3) 구한 교점으로 x의 최댓값과, 최솟값, y의 최댓값과 최솟값을 구합니다. (=갱신해나갑니다.)

2) 구한 maxx, maxy, minx, miny로 구한 교점들을 넣을 판의 height와 width를 구합니다.

3) answer= new String[height] 로 판을 만들어주고, 일단 점으로 채워줍니다. ex) "........~........"

4) set에 넣어뒀던 교점들을 순회하며 answer판에 "*" 별을 넣어줍니다.

 

 

 

>전체 코드

 

import java.util.HashSet;
import java.util.Arrays;
class Solution {
    static long minx= Long.MAX_VALUE, miny= Long.MAX_VALUE;
    static long maxx= Long.MIN_VALUE, maxy= Long.MIN_VALUE;
    
    public String[] solution(int[][] line) {
        String[] answer = {};
        HashSet<Point> pSet= new HashSet<>();
        
        //x= (bf-ed)/(ad-bc)
        //y= (ec-af)/(ad-bc)
        long x, y;
        for(int i=0; i<line.length-1; i++){
            long a= line[i][0];
            long b= line[i][1];
            long e= line[i][2];
            for(int j=i+1; j<line.length; j++){
                long c= line[j][0];
                long d= line[j][1];
                long f= line[j][2];
                
                long adbc= a*d-b*c;
                if(adbc==0) continue; //비교대상 직선과 평행함
                
                long bfed= b*f-e*d;
                if(bfed%adbc!=0) continue; //x가 정수가 아님
                
                long ecaf= e*c-a*f;
                if(ecaf%adbc!=0) continue; //y가 정수가 아님
                
                x= bfed/adbc;
                y= ecaf/adbc;
                pSet.add(new Point(x, y));
                
                minx= Math.min(minx, x);
                miny= Math.min(miny, y);
                maxx= Math.max(maxx, x);
                maxy= Math.max(maxy, y);
            }
        }
        
        long height= maxy-miny+1;
        long width= maxx-minx+1;
        answer= new String[(int)height];
        StringBuilder sb= new StringBuilder();
        for(int i=0; i<width; i++){
            sb.append(".");
        }
        
        Arrays.fill(answer, sb.toString());
        
        long nx, ny;
        for(Point p: pSet){
            ny= maxy-p.y;
            nx= p.x-minx;
            answer[(int)ny]= answer[(int)ny].substring(0, (int)nx)+"*"
                        +answer[(int)ny].substring((int)nx+1);
        }
        
        return answer;
    }
    
    public class Point{
        long x;
        long y;
        public Point(long x, long y){
            this.x= x;
            this.y= y;
        }
    }
}

https://programmers.co.kr/learn/courses/30/lessons/87377

 

코딩테스트 연습 - 10주차_교점에 별 만들기

[[2, -1, 4], [-2, -1, 4], [0, -1, 1], [5, -8, -12], [5, 8, 12]] ["....*....", ".........", ".........", "*.......*", ".........", ".........", ".........", ".........", "*.......*"] [[0, 1, -1], [1, 0, -1], [1, 0, 1]] ["*.*"] [[1, -1, 0], [2, -1, 0], [4, -

programmers.co.kr

 

[문제]

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
}

https://programmers.co.kr/learn/courses/30/lessons/86971

 

코딩테스트 연습 - 9주차_전력망을 둘로 나누기

9 [[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]] 3 7 [[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]] 1

programmers.co.kr

 

+ Recent posts