반응형

현재 필자 회사 PC의 OS는 윈도우다.


Spring boot를 이용해 개발하였고 com.spotify의 docker-maven-plugin를 통해 도커 이미지를 빌드하고자 했다.


증상은 maven clean package docker:build 명령어를 통해 이미지를 빌드하려고 하면 아래 화면에서 더 이상 진행이 되질 않는다.



걸어놓고 밥먹고 와도 그대로다. 에러메시지도 없다. 그냥 저 상태도 하염없이 멈춰있다...


폭풍 구글링을 하고, 도커데스크탑을 지웠다 다시 깔아도 보고 별 난리를 다 쳤지만 해결이 되지 않았다.

포기하려던 찰나, 플러그인이 아니라 도커 명령어로 라도 이미지를 빌드해보자라는 생각이 들었다.

그리고 그 때 발생한 에러메시지를 통해 위 증상의 원인을 알아냈다...


이미지명에 대문자 쓰면 안된단다...


혼돈의 카오스. 날려버린 나의 시간.

도커 플러그인 개발자는, 왜 에러메시지가 나오게 개발하지 않은 것이냐...


부디 이 글이 나와 같은 삽질을 하는 사람에게 한 줄기 빛이 되길 바란다.

반응형
반응형

자바를 사용할 때는 Calendar나 LocalDateTime 클래스 등을 이용하면 쉽게 날짜를 더하고 뺄 수 있다.

자바스크립트에서는 어떻게 하는 지에 대한 내용을 정리해본다.


아래와 같이 get / set 함수를 적절히 사용하면 된다.


var today = new Date(); // 오늘

var yesterday = new Date(today.setDate(today.getDate() - 1)); // 어제


today = new Date(); // 오늘

var tomorrow = new Date(today.setDate(today.getDate() + 1)); // 내일


이 방법을 알아보면서 걱정했던 건, today를 1월 1일이라고 했을 경우, today.getDate() - 1 = 0  이 된다. today를 12월 31일로 했을 경우에도 이와 비슷한 상황이 벌어진다. 다행히도 자바스크립트는 이런 값이 setter에 들어올 경우 적절히 알아서 날짜를 계산해준다.


var x = new Date('2020-01-01'); // 2020년 1월 1일

new Date(x.setDate(x.getDate() - 1)); // Tue Dec 31 2019 09:00:00 GMT+0900 (대한민국 표준시)

x = new Date('2020-12-31'); // 2020년 12월 31일 

new Date(x.setDate(x.getDate() + 1)); // Fri Jan 01 2021 09:00:00 GMT+0900 (대한민국 표준시)


달에 대해서도 사용할 수 있으면 좋으나 달의 경우 이와 같은 방법이 불가능하다.

밑의 예시를 보자.


var x = new Date('2020-01-31'); // 2020년 1월 31일

new Date(x.setMonth(x.getMonth() + 1)); // Mon Mar 02 2020 09:00:00 GMT+0900 (대한민국 표준시)


위에서 x.getMonth()의 결과는 1월을 뜻하는 0이 나온다.(달은 0 ~ 11) 따라서 setMonth(1)이 될 것이고 2020년 2월 31일이 될텐데 2월에 31일은 없으므로 3월 2일이라는 값이 나와버린다.

반응형
반응형

테스트를 위해 아래와 같이 test라는 파일을 생성한다.



아래와 같이 echo [추가할 문자열] >> [문자열을 추가할 파일명] 형태로 명령어를 입력한다.



추가 후 아래와 같이 파일이 변경된다.


반응형
반응형

타시스템의 라이브러리를 사용하는 작업을 하던 중 아래와 같은 에러메시지를 만났다.


java.lang.UnsatisfiedLinkError: libf_fcwpkg_jni.so libf_fcwpackager.so : cannot open shared object file : No such file or directory


구글링 결과, 의존성이 걸린 파일이 존재하지 않아서라는데 아래와 같이 의존성을 확인해봤다.



또 구글링을 해보니, so 파일간의 링크를 위해선 so파일들의 위치를 /etc/ld.so.conf에 추가해줘야한다고 한다. 아래와 같이 추가했다.



추가한 파일 위치의 so파일들이 바로 적용되기 위해선 ldconfig이라는 명령어를 입력해줘야한다.


- 참고- 

https://m.blog.naver.com/PostView.nhn?blogId=dae0park&logNo=221040790681&proxyReferer=https:%2F%2Fwww.google.com%2F

https://m.blog.naver.com/PostView.nhn?blogId=xoonho&logNo=40094512499&proxyReferer=https:%2F%2Fwww.google.com%2F

반응형
반응형

문제링크 : https://www.acmicpc.net/problem/1707

 

1707번: 이분 그래프

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K(2≤K≤5)가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V(1≤V≤20,000)와 간선의 개수 E(1≤E≤200,000)가 빈 칸을 사이에 두고 순서대로 주어진다. 각 정점에는 1부터 V까지 차례로 번호가 붙어 있다. 이어서 둘째 줄부터 E개의 줄에 걸쳐 간선에 대한 정보가 주어지는데, 각 줄에 인접한 두 정점의 번호가 빈 칸을 사이에 두고 주어

www.acmicpc.net

인접한 노드들을 모두 다른색(1과 -1)로 칠할 수 있는지의 여부를 체크해서 이분그래프인지 아닌지를 체크한다. 코드는 아래와 같다.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int k = Integer.parseInt(br.readLine());
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < k; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int v = Integer.parseInt(st.nextToken());
            int e = Integer.parseInt(st.nextToken());

            @SuppressWarnings("unchecked")
            List<Integer>[] lists = new ArrayList[v + 1];
            int[] color = new int[v + 1];

            for (int j = 1; j <= v; j++) {
                lists[j] = new ArrayList<Integer>();
            }

            for (int j = 0; j < e; j++) {
                st = new StringTokenizer(br.readLine());
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());

                lists[a].add(b);
                lists[b].add(a);
            }

            boolean bipartite = true;

            for (int j = 1; j <= v; j++) {
                if (color[j] == 0) {
                    if (!bfsCheck(lists, color, j)) {
                        bipartite = false;
                        break;
                    }
                    ;
                }
            }

            if (bipartite) {
                sb.append("YES\n");
            } else {
                sb.append("NO\n");
            }
        }

        System.out.println(sb);
    }

    private static boolean bfsCheck(List<Integer>[] lists, int[] color, int j) {
        Queue<Integer> queue = new LinkedList<Integer>();
        queue.offer(j);
        color[j] = 1;

        while (!queue.isEmpty()) {
            int n = queue.poll();

            for (int elem : lists[n]) {
                if (color[elem] == 0) {
                    queue.offer(elem);
                    color[elem] = color[n] * -1;
                } else if (color[elem] != color[n] * -1) {
                    return false;
                }
            }
        }

        return true;
    }
}

 

반응형
반응형

문제링크 : https://www.acmicpc.net/problem/1167

 

1167번: 트리의 지름

트리가 입력으로 주어진다. 먼저 첫 번째 줄에서는 트리의 정점의 개수 V가 주어지고 (2≤V≤100,000)둘째 줄부터 V개의 줄에 걸쳐 간선의 정보가 다음과 같이 주어진다. (정점 번호는 1부터 V까지 매겨져 있다고 생각한다) 먼저 정점 번호가 주어지고, 이어서 연결된 간선의 정보를 의미하는 정수가 두 개씩 주어지는데, 하나는 정점번호, 다른 하나는 그 정점까지의 거리이다. 예를 들어 네 번째 줄의 경우 정점 3은 정점 1과 거리가 2인 간선으로 연결되

www.acmicpc.net

트리의 지름을 구하는 문제다. 트리의 지름이란, 트리에서 가장 멀리 떨어져있는 두 노드 사이의 길이를 말한다.

 

트리의 지름을 구하는 방법은, 임의의 노드 x에서 DFS 백트래킹을 통해 가장 멀리 떨어져있는 노드 y를 구한 후, y에서 다시 DFS 백트래킹을 통해 가장 멀리 떨어져있는 노드 z를 구하면, y에서 z사이의 거리가 바로 트리의 지름이 된다. 이에 대한 증명을 해보자 -> (업데이트 예정)

 

코드는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
 
public class Main {
    private static int max = 0;
    private static int start = 0;
    
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int v = Integer.parseInt(br.readLine());
        
        @SuppressWarnings("unchecked")
        List<Link>[] lists = new ArrayList[v + 1];
        
        for(int i = 1; i <= v; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int n = Integer.parseInt(st.nextToken());
            lists[n] = new ArrayList<Link>();
            
            while(true) {
                int m = Integer.parseInt(st.nextToken());
                
                if(m == -1break;
                
                lists[n].add(new Link(m, Integer.parseInt(st.nextToken())));
            }
        }
                
        boolean[] visited = new boolean[v + 1];
        dfs(lists, visited, 10);
        
        visited = new boolean[v + 1];
        dfs(lists, visited, start, 0);
        
        System.out.println(max);
    } 
    
    private static void dfs(List<Link>[] lists, boolean[] visited, int i, int length) {
        visited[i] = true;
        
        if(length > max) {
            max = length;
            start = i;
        }
        
        for(Link next : lists[i]) {
            int m = next.getM();
            int distance = next.getDistance();
            
            if(!visited[m]) {
                dfs(lists, visited, m, length + distance);
                visited[m] = false;
            }
        }
    }
 
    private static class Link {
        private int m;
        private int distance;
        
        public Link(int m, int distance) {
            this.m = m;
            this.distance = distance;
        }
 
        public int getM() {
            return m;
        }
 
        public int getDistance() {
            return distance;
        }    
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

반응형
반응형

문제링크 : https://www.acmicpc.net/problem/2873

 

2873번: 롤러코스터

문제 상근이는 우리나라에서 가장 유명한 놀이 공원을 운영하고 있다. 이 놀이 공원은 야외에 있고, 다양한 롤러코스터가 많이 있다. 어느 날 벤치에 앉아있던 상근이는 커다란 황금을 발견한 기분이 들었다. 자신의 눈 앞에 보이는 이 부지를 구매해서 롤러코스터를 만든다면, 세상에서 가장 재미있는 롤러코스터를 만들 수 있다고 생각했다. 이 부지는 직사각형 모양이고, 상근이는 R행 C열의 표 모양으로 나누었다. 롤러코스터는 가장 왼쪽 위 칸에서 시작할 것이고, 가

www.acmicpc.net

필자가 싫어하는 그리디 유형이다...-_- 그리디 유형은 모든 경우의 수를 하나도 빠뜨림없이 고려하며, 각각의 경우의 수마다 규칙성을 찾고 그에 알맞게 코딩을 해야한다. 흐어... 그럼 설명을 시작해보도록 하겠다.

 

일단 연습장에 조금만 끄적여보다보면, 가로나 세로의 길이가 홀수일 경우, 모든 칸을 지나는 것이 가능하다는 것을 눈치챌 수 있을 것이다. 모든 칸을 지나갈 때의 점수보다 더 큰 점수를 만들 수는 없을 것이므로 이 때의 경로가 답이 된다. 그냥 지그재그로 움직이면 된다.

문제는 가로와 세로의 길이 모두 짝수일 때다. 이 때는 아무리 끄적거려봐도 모든 칸을 지나가는 것이 불가능하다. 조금 더 끄적거리다보면, 한 칸만 비워놓고 모든 칸을 지나가는 것은 가능하다는 것을 깨닫게 될 것이고, 빈 칸이 될 수 있는 칸은 아래 그림의 초록색 칸들이다.

초록색 칸은 i + j 가 홀수일 때다. 이 초록색 칸들 중에서 가장 낮은 점수를 가지고 있는 칸을 찾아서, 그 칸을 제외한 모든 칸을 지나가는 경로를 찾으면 점수가 최대인 경로를 얻게된다. 여기까지 생각해내는 건 쉽다. 이제 그 경로를 어떻게 찾아낼 수 있는지를 생각해내야하는데, 그게 좀 머리가 아프다...-_- 그 방법에 대해서는... 아래 코드를 보며 이해를 해보도록 하자^^;;;

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
 
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int r = Integer.parseInt(st.nextToken());
        int c = Integer.parseInt(st.nextToken());
        
        if((r & 1== 0 && (c & 1== 0) {
            int minI = 0;
            int minJ = 0;
            int min = Integer.MAX_VALUE;
            
            for(int i = 0; i < r; i++) {
                st = new StringTokenizer(br.readLine());
                
                for(int j = 0; j < c; j++) {
                    if(((i + j) & 1== 1) {
                        int n = Integer.parseInt(st.nextToken());
                        
                        if(min > n) {
                            min = n;
                            minI = i;
                            minJ = j;
                        }
                    } else {
                        st.nextToken();
                    }
                }
            }
            
            System.out.println(getAnswer(r, c, minI, minJ));
        } else {
            for(int i = 0; i < r; i++) {
                br.readLine();
            }
            
            if((r & 1== 1) {
                System.out.println(getZigZag('R''L''D', c, r).deleteCharAt(r * c - 1));
            } else {
                System.out.println(getZigZag('D''U''R', r, c).deleteCharAt(r * c - 1));
            }
        }
    }
 
    private static String getAnswer(int r, int c, int minI, int minJ) {
        StringBuffer sb = new StringBuffer();
        int tmp = minI / 2 * 2;        
        sb.append(getZigZag('R''L''D', c, tmp));
        
        for(int i = 0; i < minJ; i++) {
            if((i & 1== 0 ) {
                sb.append("DR");
            } else {
                sb.append("UR");
            }
        }
        
        for(int i = minJ; i < c - 1; i++) {
            if((i & 1== 0 ) {
                sb.append("RD");
            } else {
                sb.append("RU");
            }
        }
        
        sb.append('D');
        sb.append(getZigZag('L''R''D', c, r - tmp - 2));
        
        return sb.deleteCharAt(sb.length() - 1).toString();
    }
 
    private static StringBuffer getZigZag(char f, char b, char d, int c, int r) {
        StringBuffer sb = new StringBuffer();
        
        for(int i = 0; i < r; i++) {
            for(int j = 0; j < c - 1; j++) {
                if((i & 1== 0) {
                    sb.append(f);
                } else {
                    sb.append(b);
                }
            }
            
            sb.append(d);
        }
        
        return sb;
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 

반응형
반응형

문제링크 : https://www.acmicpc.net/problem/2579

 

2579번: 계단 오르기

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다. 예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다. 계단 오르는 데는 다음과 같은 규칙이 있다. 계단은 한 번에 한 계단씩

www.acmicpc.net

필자는 이 문제의 출처가 정보올림피아드 '초등부'라는 걸 알았는데 꽤나 충격을 받았다... 난 초등학교 때 뭐했지...ㅠㅠ 각설하고, 설명을 해보도록 하겠다.

 

이 문제는 메모이제이션을 통한 다이나믹 프로그래밍 문제이다. 그렇다면 대체 무엇을 메모리에 남겨야할까?! 바로 각 계단까지 올라왔을 때의 점수의 최댓값이다. 코드는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[] scores = new int[300];
        int[] max = new int[300];
        
        for(int i = 0; i < n; i++) {
            scores[i] = Integer.parseInt(br.readLine());
        }
        
        max[0= scores[0];
        max[1= scores[0+ scores[1];
        max[2= Math.max(scores[0], scores[1]) + scores[2];
        
        for(int i = 3; i < n; i++) {
            max[i] = Math.max(max[i - 2], max[i - 3+ scores[i - 1]) + scores[i];
        }
        
        System.out.println(max[n - 1]);
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

0, 1, 2 번째 계단까지 올라갔을 때 얻을 수 있는 최댓값에 대한 식은 다들 무리없이 이해할 수 있으리라고 본다. 그 다음 로직에 대해서 설명을 하면, i번째 계단에 오르기 위해선 i - 1번째 계단이나 i - 2번째 계단 둘 중 하나에서 올라와야한다. 두 가지 경우 중, 큰 값을 가지는 경우를 max값에 넣으면 된다. 근데 i - 1번째에서 올라올 경우, max[i - 1]의 값이 바로 i - 2번째 계단을 선택한 값인지 아닌지를 알 수가 없다. (i - 2번째 계단을 선택한 최댓값일 경우, i를 선택할 수 없으므로) 헌데 i번째, i - 1번째 계단 둘을 선택할 경우, i - 2번째 계단을 선택할 수는 없으므로 i - 3번째에서 왔을 것이다. 따라서 i - 1번째 계단에서 올라왔을 경우는 i - 1번째 계단의 점수와 i - 3번째 점수의 최댓값을 더하면 된다.

조금 다른 방식으로 풀 수도 있다. max를 2차원 배열로 선언하여, 바로 다음 계단을 선택할 수 있을 경우의 최댓값과 없는 경우의 최댓값을 저장하는 것이다. 코드는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        int[] scores = new int[300];
        int[][] max = new int[2][300];
        
        for(int i = 0; i < n; i++) {
            scores[i] = Integer.parseInt(br.readLine());
        }
        
        max[0][0= scores[0];
        max[0][1= scores[1];
        max[1][1= scores[0+ scores[1];
        
        for(int i = 2; i < n; i++) {
            max[0][i] = Math.max(max[0][i - 2], max[1][i - 2]) + scores[i];
            max[1][i] = max[0][i - 1+ scores[i];
        }
        
        System.out.println(Math.max(max[0][n - 1], max[1][n - 1]));
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

반응형

+ Recent posts