<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Noooodle's Footprints</title>
    <link>https://noooodlefts.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 6 Apr 2026 09:27:39 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Noooodle</managingEditor>
    <image>
      <title>Noooodle's Footprints</title>
      <url>https://tistory1.daumcdn.net/tistory/6786441/attach/c1c73798a2274695a1c72fe6f1554222</url>
      <link>https://noooodlefts.tistory.com</link>
    </image>
    <item>
      <title>Apache Tomcat 8.5.3 설치</title>
      <link>https://noooodlefts.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://archive.apache.org/dist/tomcat/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://archive.apache.org/dist/tomcat/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731308521656&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Index of /dist/tomcat&quot; data-og-description=&quot;&quot; data-og-host=&quot;archive.apache.org&quot; data-og-source-url=&quot;https://archive.apache.org/dist/tomcat/&quot; data-og-url=&quot;https://archive.apache.org/dist/tomcat/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://archive.apache.org/dist/tomcat/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://archive.apache.org/dist/tomcat/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Index of /dist/tomcat&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;archive.apache.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQuMyd/btsKDEeq7WP/v5jqGIkvkk9kUkSBhvukPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQuMyd/btsKDEeq7WP/v5jqGIkvkk9kUkSBhvukPK/img.png&quot; data-alt=&quot;맞는 버전 찾기1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQuMyd/btsKDEeq7WP/v5jqGIkvkk9kUkSBhvukPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQuMyd%2FbtsKDEeq7WP%2Fv5jqGIkvkk9kUkSBhvukPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;373&quot; height=&quot;228&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;맞는 버전 찾기1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjLIgo/btsKD260Ypx/wZPILAni2O3z45TcyaJnhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjLIgo/btsKD260Ypx/wZPILAni2O3z45TcyaJnhk/img.png&quot; data-alt=&quot;OS환경 맞춰서 다운로드&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjLIgo/btsKD260Ypx/wZPILAni2O3z45TcyaJnhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjLIgo%2FbtsKD260Ypx%2FwZPILAni2O3z45TcyaJnhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;510&quot; height=&quot;559&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;OS환경 맞춰서 다운로드&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;465&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSm6VE/btsKFqlfAR6/6m16uOMkSbaaQZCk1TFHMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSm6VE/btsKFqlfAR6/6m16uOMkSbaaQZCk1TFHMk/img.png&quot; data-alt=&quot;톰캣 위치 정하고 zip파일 풀기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSm6VE/btsKFqlfAR6/6m16uOMkSbaaQZCk1TFHMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSm6VE%2FbtsKFqlfAR6%2F6m16uOMkSbaaQZCk1TFHMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;677&quot; height=&quot;465&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;톰캣 위치 정하고 zip파일 풀기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3iH1i/btsKDEeruL0/WK05Lg1p9yLmHaYkrfcLk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3iH1i/btsKDEeruL0/WK05Lg1p9yLmHaYkrfcLk1/img.png&quot; data-alt=&quot;톰캣설치경로/bin 에서 ./service.bat install 하면 끝&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3iH1i/btsKDEeruL0/WK05Lg1p9yLmHaYkrfcLk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3iH1i%2FbtsKDEeruL0%2FWK05Lg1p9yLmHaYkrfcLk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;171&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;톰캣설치경로/bin 에서 ./service.bat install 하면 끝&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고자료 : &lt;a href=&quot;https://byounghee.tistory.com/224&quot;&gt;https://byounghee.tistory.com/224&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1731308796531&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Windows(윈도우) 에서 Tomcat 설치 및 실행 방법&quot; data-og-description=&quot;Windows(윈도우) 에서 Tomcat 설치 및 실행 방법 이번 게시글에서는 파일 업로드 취약점 실습 시 필요한 환경 구축을 진행할 예정이며, Windows(윈도우)에서 Tomcat 설치 및 실행 방법에 대해서 알아본다.&quot; data-og-host=&quot;byounghee.tistory.com&quot; data-og-source-url=&quot;https://byounghee.tistory.com/224&quot; data-og-url=&quot;https://byounghee.tistory.com/224&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/rX75F/hyXwl6gVHz/EKsmZdDPKPRsduJRhHBvQk/img.png?width=800&amp;amp;height=536&amp;amp;face=0_0_800_536,https://scrap.kakaocdn.net/dn/UTIUp/hyXwqsXLR7/qdvkQ4HKVZ8VbuWiUJvBhK/img.png?width=800&amp;amp;height=536&amp;amp;face=0_0_800_536&quot;&gt;&lt;a href=&quot;https://byounghee.tistory.com/224&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://byounghee.tistory.com/224&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/rX75F/hyXwl6gVHz/EKsmZdDPKPRsduJRhHBvQk/img.png?width=800&amp;amp;height=536&amp;amp;face=0_0_800_536,https://scrap.kakaocdn.net/dn/UTIUp/hyXwqsXLR7/qdvkQ4HKVZ8VbuWiUJvBhK/img.png?width=800&amp;amp;height=536&amp;amp;face=0_0_800_536');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Windows(윈도우) 에서 Tomcat 설치 및 실행 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Windows(윈도우) 에서 Tomcat 설치 및 실행 방법 이번 게시글에서는 파일 업로드 취약점 실습 시 필요한 환경 구축을 진행할 예정이며, Windows(윈도우)에서 Tomcat 설치 및 실행 방법에 대해서 알아본다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;byounghee.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>기타</category>
      <category>apachetomcat</category>
      <category>Java</category>
      <category>tomcat</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/92</guid>
      <comments>https://noooodlefts.tistory.com/92#entry92comment</comments>
      <pubDate>Mon, 11 Nov 2024 16:07:07 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]Client-Server Socket 통신, N:1 다중 클라이언트, 멀티스레드</title>
      <link>https://noooodlefts.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;서버-클라이언트 연결중에, 클라이언트가 먼저 종료되면 보통 서버는 살아있다. 근데 반대로 서버가 죽은 경우에는? 클라이언트도 종료되지만, 서버가 다시 살아났을때 클라이언트가 연결할 수 있도록 해보자..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다중 클라이언트, 멀티스레드 환경, 클라이언트-서버 연결 중에 서버가 먼저 끝난 경우. 클라이언트 재연결 시도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730797445887&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package client;

import client.domain.*;

import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Clients {
    private static final String SERVER_ADDRESS = &quot;localhost&quot;; // 서버 주소
    private static final int SERVER_PORT = 12345; // 서버 포트 번호
    private static final int MILLISECOND = 1000;

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5); // 최대 5개의 동시작업 가능한 스레드 풀

        executor.execute(new TimeClient()); // 시간 클라이언트 : 1초마다 TimeInfo 객체 전송
		// .. 다른 스레드 생략 

        executor.shutdown(); // 스레드풀 종료, 현재 처리중인 작업, 작업 큐에 대기하는 모든 작업을 처리한 뒤 종료
}

static class TimeClient implements Runnable {

        @Override
        public void run() {
            do {
                try (Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT);
                     ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); // 직렬화&amp;amp;역직렬화 관련 IO
                     ObjectInputStream in = new ObjectInputStream(socket.getInputStream())) {
                    
                    System.out.println(&quot;시간 클라이언트와 뉴스 서버가 연결되었습니다.&quot;);

                    while (true) {
                        // 클라이언트 - 서버 통신 내용.. 생략
                    }
                    
                } catch (SocketException e) { // 소켓이 닫혔을때 = 즉, 서버가 실행중이 아님
                    System.out.println(&quot;뉴스 서버가 종료되었습니다.&quot;);
                } catch (InterruptedException | ClassNotFoundException | IOException e) {
                    e.printStackTrace();
                }

                // 서버 재연결 전에 잠시 기다림 -&amp;gt; 1.1초 안에 서버가 살아나면 다시 연결됨
                try {
                    Thread.sleep((long) (MILLISECOND * 1.1));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            } while (true); // 서버와 재연결 무한반복..
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 코드는 생략.. 귀찮으니까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 클라이언트 역할을 수행하는 스레드를 socket이 종료되었다고 바로 끝내지 않고, &lt;b&gt;do while문을 통해 서버 접속을 시도하는 것&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소켓 연결이 끊겨서 소켓이 끝나는 것과 스레드가 끝나는 것은 다르다.. 이걸 이해못해서 고생함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 코드에서는 재연결 시도 횟수를 3회로 주어서 3회까지 연결해보고 안되면 스레드를 종료한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnJJZt/btsKxxFDvx7/uazUvFxoTPqa5bhcJ9CzWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnJJZt/btsKxxFDvx7/uazUvFxoTPqa5bhcJ9CzWk/img.png&quot; data-alt=&quot;실제 작동 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnJJZt/btsKxxFDvx7/uazUvFxoTPqa5bhcJ9CzWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnJJZt%2FbtsKxxFDvx7%2FuazUvFxoTPqa5bhcJ9CzWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1800&quot; height=&quot;665&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;실제 작동 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>기타</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/91</guid>
      <comments>https://noooodlefts.tistory.com/91#entry91comment</comments>
      <pubDate>Tue, 5 Nov 2024 18:13:14 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 9934, 완전 이진 트리</title>
      <link>https://noooodlefts.tistory.com/90</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfBziL/btsJIlezIIP/2el0LNMYtplONW3qxlyWj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfBziL/btsJIlezIIP/2el0LNMYtplONW3qxlyWj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfBziL/btsJIlezIIP/2el0LNMYtplONW3qxlyWj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfBziL%2FbtsJIlezIIP%2F2el0LNMYtplONW3qxlyWj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1038&quot; height=&quot;848&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;inoder로 들어온 완전이진트리를 트리의 모습.. 음 레벨 순회로 각 레벨마다 줄바꿈해서 출력하면 된다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class BOJ9934 {
    public static void getTree(int[] arr, int start, int end, int level, List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; levels){
        int middle;

        if(start &amp;lt;= end){
            middle = (start + end) / 2;
            levels.get(level).add(arr[middle]); // 자기 자신을 먼저 저장

            getTree(arr, start, middle - 1, level + 1, levels); // 자기자신을 기준으로 왼쪽 순회
            getTree(arr, middle + 1, end, level + 1, levels); // 자기자신을 기준으로 오른쪽 순회
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; levels = new ArrayList&amp;lt;&amp;gt;();
        StringTokenizer st;
        int n, i, cnt = 1;
        int[] arr;

        // 노드 개수 구하기
        n = Integer.parseInt(br.readLine());
        for(i=0;i&amp;lt;n;i++)
            cnt *=2;
        cnt = cnt - 1;

        // 입력값(inorder결과) 저장하기
        arr = new int[cnt];
        st = new StringTokenizer(br.readLine());
        for (i = 0; i &amp;lt; cnt; i++)
            arr[i] = Integer.parseInt(st.nextToken());

        // 레벨별로 노드를 저장할 리스트 생성
        for (i = 0; i &amp;lt; n; i++)
            levels.add(new ArrayList&amp;lt;&amp;gt;()); // 각 레벨에 해당하는 리스트 생성

        getTree(arr, 0, cnt - 1, 0, levels);

        // 각 레벨별로 출력
        for(i=0;i&amp;lt;n;i++){
            for(int value : levels.get(i))
                System.out.print(value + &quot; &quot;);
            System.out.println();  // 레벨별로 줄바꿈
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리를 찾는것 자체는 어렵지 않지만, 출력이 까다롭다.. 리스트를 만들어서 레벨별로 자기자신 노드를 저장해줬다.&lt;/p&gt;</description>
      <category>코딩가딩가</category>
      <category>Inorder</category>
      <category>Java</category>
      <category>recursion</category>
      <category>Tree</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/90</guid>
      <comments>https://noooodlefts.tistory.com/90#entry90comment</comments>
      <pubDate>Sun, 22 Sep 2024 21:19:42 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 1967, 트리의 지름</title>
      <link>https://noooodlefts.tistory.com/89</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQ3uBc/btsJIQkSiCd/qEttlSKZrHm10hrUbxJHNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQ3uBc/btsJIQkSiCd/qEttlSKZrHm10hrUbxJHNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQ3uBc/btsJIQkSiCd/qEttlSKZrHm10hrUbxJHNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQ3uBc%2FbtsJIQkSiCd%2FqEttlSKZrHm10hrUbxJHNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1165&quot; height=&quot;862&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어렵다.. 골드였구나&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 트리를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. dfs를 두 번 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게만 보면 간단해보이는데.. 구현하는게 어려웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 트리를 만든다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;ArrayList&amp;lt;Node&amp;gt;[] tree; // 선언

// 트리 초기화
tree = new ArrayList[n + 1];
for(i=0;i&amp;lt;=n;i++) // 1번 노트부터 사용하지만 null포인터 에러나서 [0]도 초기화함
    tree[i] = new ArrayList&amp;lt;&amp;gt;();

// 트리 만들기 -&amp;gt; 간선개수는 노드개수 -1
for(i=1;i&amp;lt;n;i++) {
    st = new StringTokenizer(br.readLine());
    parent = Integer.parseInt(st.nextToken());
    child = Integer.parseInt(st.nextToken());
    weight = Integer.parseInt(st.nextToken());
    // 부모-자식 사이 간선 추가
    tree[parent].add(new Node(child, weight));
    tree[child].add(new Node(parent, weight));
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 문제는 ArrayList로 트리를 구현한다. 트리를 초기화할때 i=1부터 했더니 자꾸 NullPointer가 발생해서 i=0으로 바꿨다. 바꿨더니 에러가 안나고 정답을 맞췄다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList에 tree[부모]에&amp;nbsp; '부모, 자식, 간선가중치'를 저장한다. 그리고 부모-자식이 연결됐다는건 자식-부모도 연결되어있다는 뜻이므로 tree[자식]에 '자식, 부모, 간선가중치'를 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 3 , 1 2 3, 1 3 5 라면 tree[1]에는 1과 2가 3의 거리이고 1과 3이 5의 거리인게 저장될것이다. 그리고 tree[2]에는 2와 1이 3의 거리인게 저장된다. tree[3]에는 3과 1이 5의 거리인게 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. dfs 메소드와 main에서 dfs호출&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Node {
    int vertex, weight;

    public Node(int vertex, int weight) {
        this.vertex = vertex;
        this.weight = weight;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 노드 클래스이다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static void dfs(ArrayList&amp;lt;Node&amp;gt;[] tree, int node, int dist, int[] maxDist, int[] fatrhestNode, boolean[] visited){
    visited[node] = true;

    if(dist &amp;gt; maxDist[0]){ // 현재까지 거리가 제일 긴 거리보다 길때 바꿔줘야함
        maxDist[0] = dist;
        fatrhestNode[0] = node;
    }

    for(Node next : tree[node]){
        if(!visited[next.vertex]) // 방문되지 않았을때만 진행
            dfs(tree, next.vertex, dist + next.weight, maxDist, fatrhestNode, visited); // 다음 노드로 넘어간 만큼 가중치를 더해 재귀
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 총 2번의 DFS 실행
// 1번째 DFS
visited = new boolean[n + 1];
dfs(tree, 1, 0, maxDist, farthestNode, visited);

// 2번째 DFS
maxDist[0] = 0;  // 거리 다시 초기화
visited = new boolean[n + 1];
dfs(tree, farthestNode[0], 0, maxDist, farthestNode, visited);

System.out.println(maxDist[0]);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 긴 지름을 구하기 위해서는.. 두 번의 dfs를 진행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째에 임의의 지점에서 &lt;b&gt;제일 먼 노드&lt;/b&gt;를 찾는다.(보통 루트에서 시작함) 두번째에 첫번째 dfs에서 찾은 &lt;b&gt;제일 먼 노드&lt;/b&gt;에서 제일 먼 노드2를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때의 거리(가중치)를 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 전역변수를 많이 쓰는데.. 나는 C언어로 코딩을 처음 배워서 전역변수보다는 포인터에 익숙해 전역변수를 쓰지 않았다. 근데 자바에는 포인터가 없으니까... 고민하다가 그냥 1칸짜리 배열을 만들어서 매개변수로 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각해내는 것도 어렵고, 구현하는 것도 어렵지만 하나씩 차근차근 보고 이해하면 완성할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 전체 코드이다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class BOJ1967 {
    public static void dfs(ArrayList&amp;lt;Node&amp;gt;[] tree, int node, int dist, int[] maxDist, int[] fatrhestNode, boolean[] visited){
        visited[node] = true;

        if(dist &amp;gt; maxDist[0]){
            maxDist[0] = dist;
            fatrhestNode[0] = node;
        }

        for(Node next : tree[node]){
            if(!visited[next.vertex])
                dfs(tree, next.vertex, dist + next.weight, maxDist, fatrhestNode, visited);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        ArrayList&amp;lt;Node&amp;gt;[] tree;
        StringTokenizer st;
        boolean[] visited;
        int n, i, parent, child, weight;
        int [] farthestNode = {0};
        int [] maxDist = {0};

        n = Integer.parseInt(br.readLine());

        // 트리 초기화
        tree = new ArrayList[n + 1];
        for (i = 0; i &amp;lt;= n; i++) { // 1번 노트부터 사용하지만 null포인터 에러나서 [0]도 초기화함
            tree[i] = new ArrayList&amp;lt;&amp;gt;();
        }

        // 트리 만들기 -&amp;gt; 간선개수는 노드개수 -1
        for(i=1;i&amp;lt;n;i++) {
            st = new StringTokenizer(br.readLine());
            parent = Integer.parseInt(st.nextToken());
            child = Integer.parseInt(st.nextToken());
            weight = Integer.parseInt(st.nextToken());
            // 부모-자식 사이 간선 추가
            tree[parent].add(new Node(child, weight));
            tree[child].add(new Node(parent, weight));
        }

        // 총 2번의 DFS 실행
        // 1번째 DFS
        visited = new boolean[n + 1];
        dfs(tree, 1, 0, maxDist, farthestNode, visited);

        // 2번째 DFS
        maxDist[0] = 0;  // 거리 다시 초기화
        visited = new boolean[n + 1];
        dfs(tree, farthestNode[0], 0, maxDist, farthestNode, visited);

        System.out.println(maxDist[0]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Node {
    int vertex, weight;

    public Node(int vertex, int weight) {
        this.vertex = vertex;
        this.weight = weight;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <category>코딩가딩가</category>
      <category>dfs</category>
      <category>Java</category>
      <category>Tree</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/89</guid>
      <comments>https://noooodlefts.tistory.com/89#entry89comment</comments>
      <pubDate>Sun, 22 Sep 2024 16:39:34 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 1991, 트리 순회</title>
      <link>https://noooodlefts.tistory.com/88</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1175&quot; data-origin-height=&quot;745&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKQeov/btsJIrFs6pf/tODU5VLb09hSETFCW7TRxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKQeov/btsJIrFs6pf/tODU5VLb09hSETFCW7TRxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKQeov/btsJIrFs6pf/tODU5VLb09hSETFCW7TRxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKQeov%2FbtsJIrFs6pf%2FtODU5VLb09hSETFCW7TRxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1175&quot; height=&quot;745&quot; data-origin-width=&quot;1175&quot; data-origin-height=&quot;745&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리를 구현하고 순회하는 단순한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리를 구현할때.. 클래스가 3개 필요하다. 메인, node, binaryTree&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. node 클래스&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Node {
    char data;
    Node left;
    Node right;

    Node(char data){
        this.data = data;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순하게 노드를 구현한다. 자기자신과 왼쪽노드, 오른쪽노드를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. BinaryTree 클래스&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.util.HashMap;

public class BinaryTree {
    private Node root; // 루트 노드
    private HashMap&amp;lt;Character, Node&amp;gt; nodes; // 각 노드를 저장하는 맵, 간선 역할

    public BinaryTree() {
        nodes = new HashMap&amp;lt;&amp;gt;();
    }

    public Node getRoot(){ // 루트 반환
        return root;
    }

    public void add(char parent, char left, char right){
        if(!nodes.containsKey(parent)) // 부모노드가 존재하지 않으면 생성
            nodes.put(parent, new Node(parent));

        Node parentNode = nodes.get(parent); // 부모노드 저장

        if(left != '.'){ // 왼쪽 자식이 있다면
            parentNode.left = new Node(left); // 부모노드에 왼쪽노드 생성해서 연결하고
            nodes.put(left, parentNode.left); // nodes 맵에 저장
        }

        if(right != '.'){ // 오른쪽 자식이 있다면
            parentNode.right = new Node(right); // 부모노드에 오른쪽노드 생성해서 연결하고
            nodes.put(right, parentNode.right); // nodes 맵에 저장
        }

        if(root == null) // 루트 지정하기
            root = parentNode;
    }

    public void preorder(Node node){ // 전위 순회
        if(node == null) return;
        System.out.print(node.data);
        preorder(node.left);
        preorder(node.right);
    }

    public void inorder(Node node){ // 중위 순회
        if(node == null) return;
        inorder(node.left);
        System.out.print(node.data);
        inorder(node.right);
    }

    public void postorder(Node node){ // 후위 순회
        if(node == null) return;
        postorder(node.left);
        postorder(node.right);
        System.out.print(node.data);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시맵이 연결해주는 &lt;b&gt;간선&lt;/b&gt; 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메소드는 루트를 반환하는 getRoot, 노드를 생성하고 연결하는 add, 순회방법 3가지 preorder, inorder, postorder 이렇게 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 메인&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class BOJ1991 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N, i;
        BinaryTree tree = new BinaryTree();
        StringTokenizer st;

        N = Integer.parseInt(br.readLine());
        for(i=0;i&amp;lt;N;i++){
            st = new StringTokenizer(br.readLine());
            tree.add(st.nextToken().charAt(0), st.nextToken().charAt(0), st.nextToken().charAt(0));
        }

        tree.preorder(tree.getRoot());
        System.out.println();

        tree.inorder(tree.getRoot());
        System.out.println();

        tree.postorder(tree.getRoot());
        System.out.println();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인에서는 문제에서 주어진대로 입력을 받고, tree.add를 호출해 노드를 만들고 연결시킨다. 그리고 세가지 방법으로 순회를 한다.&lt;/p&gt;</description>
      <category>코딩가딩가</category>
      <category>Java</category>
      <category>Tree</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/88</guid>
      <comments>https://noooodlefts.tistory.com/88#entry88comment</comments>
      <pubDate>Sat, 21 Sep 2024 20:08:42 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 11725, 트리의 부모 찾기</title>
      <link>https://noooodlefts.tistory.com/87</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;299&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dINd83/btsJuTiGYff/38xJOZjnpmyIZUSmHTSz1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dINd83/btsJuTiGYff/38xJOZjnpmyIZUSmHTSz1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dINd83/btsJuTiGYff/38xJOZjnpmyIZUSmHTSz1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdINd83%2FbtsJuTiGYff%2F38xJOZjnpmyIZUSmHTSz1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1158&quot; height=&quot;299&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;299&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리를 활용한 간단한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리에 대해 짧게 요약하고 넘어가자면 ..&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;트리 : 순환이 없는 그래프&lt;br /&gt;트리종류 : 일반트리 이진트리 N-진트리 균형트리 힙.. 등이 있음 &lt;br /&gt;순회방법 : preorder, inorder, postorder, levelorer 등이 있음 &lt;br /&gt;dfs, bfs : 그래프와 트리에 사용할 수 있는 탐색 알고리즘 &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- dfs : preorder, inorder, postorder 방식으로 탐색 가능 &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- bfs : leveloder와 같음&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 트리를 구현할때는 리스트를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 리스트를 이용해 빈 노드를 가진 트리를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 노드에 간선을 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. DFS 탐색(preorder)으로 부모를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 부모를 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 메인 -&amp;gt; &lt;b&gt;2. 노드에 간선 추가&lt;/b&gt;와 &lt;b&gt;3. DFS탐색&lt;/b&gt;은 함수로 따로 뺐다.&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N, i;
        StringTokenizer st;

        N = Integer.parseInt(br.readLine());
        List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; graph = new ArrayList&amp;lt;&amp;gt;();
        int[] parentArr = new int[N + 1];
        int[] visited = new int[N + 1];

        // 그래프에 노드 추가 -&amp;gt; 0번은 사용하지 않음
        for(i=0;i&amp;lt;=N;i++)
            graph.add(new ArrayList&amp;lt;&amp;gt;());

        // 노드에 간선 추가
        for(i=0;i&amp;lt;N-1;i++){
            st = new StringTokenizer(br.readLine());
            addEdge(graph, Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
        }

        // DFS -&amp;gt; preoder 로 부모 탐색
        DFS(parentArr, visited, graph, 1);

        // 0번째 노드와 루트는 제외하고 출력
        for(i=2;i&amp;lt;=N;i++)
            System.out.println(parentArr[i]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. addEdge함수 -&amp;gt; 노드에 간선 추가&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public static void addEdge(List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; graph, int u, int v) {
    // 무방향 그래프이므로 양방향 추가
    graph.get(u).add(v);
    graph.get(v).add(u);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방향이 없는 그래프이므로 간선을 추가한다. GPT가 설명을 잘 해줘서 캡쳐로 설명추가&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRuWl3/btsJt8BkxH3/EQ5wNiCmjbjPkAKBXVROr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRuWl3/btsJt8BkxH3/EQ5wNiCmjbjPkAKBXVROr1/img.png&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;482&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.0076%; margin-right: 10px;&quot; data-widthpercent=&quot;48.57&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRuWl3/btsJt8BkxH3/EQ5wNiCmjbjPkAKBXVROr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRuWl3%2FbtsJt8BkxH3%2FEQ5wNiCmjbjPkAKBXVROr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;734&quot; height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceWVSj/btsJuegVSE5/qBSSgVQz6fdrSPDKNHkEQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceWVSj/btsJuegVSE5/qBSSgVQz6fdrSPDKNHkEQ0/img.png&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;454&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.8296%;&quot; data-widthpercent=&quot;51.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceWVSj/btsJuegVSE5/qBSSgVQz6fdrSPDKNHkEQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceWVSj%2FbtsJuegVSE5%2FqBSSgVQz6fdrSPDKNHkEQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;732&quot; height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. DFS함수 -&amp;gt; preoder방식&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;public static void DFS(int[] parentArr, int[] visited, List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; graph, int node){
    // preoder 방식
    visited[node] = 1;

    for(int neighbor : graph.get(node)){ // node와 인접한 노드(neighbor) 탐색하기
        if(visited[neighbor] == 0){ // 탐색되지 않았다면
            parentArr[neighbor] = node; // neighbor는 node의 자식임
            DFS(parentArr, visited, graph, neighbor); // neighbor를 node로해서 재귀 탐색
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, node(노드번호)가 들어왔을때 탐색했다고 저장한다(visited[node] = 1). 그리고 node와 인접한 노드들이 탐색이 되었는지 확인한다. 인접한 노드를 neighbor라고 한다. neighbor가 탐색이 되지 않았다면, node는 neighbor의 부모이다. 그래서 parentArr[neighbor] = node라고 부모를 저장해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 GPT가 든 예시로 설명하면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjbhoR/btsJt6XNPu9/7Lcliyr6WNjbYsne7C8I7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjbhoR/btsJt6XNPu9/7Lcliyr6WNjbYsne7C8I7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjbhoR/btsJt6XNPu9/7Lcliyr6WNjbYsne7C8I7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjbhoR%2FbtsJt6XNPu9%2F7Lcliyr6WNjbYsne7C8I7K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;171&quot; height=&quot;154&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node = 1이고, 인접한 노드(neighbor = graph.get(node)))는 [2, 3] 이므로 처음에는 2, 두 번째는 3이 될것이다. 노드1(현재 node = 1이므로)은 탐색되었다고 표시하고 인접한 노드 중, 첫번째인 2를 neighbor로 지정한다. neighbor(노드2)는 아직 탐색되지 않았으므로 if문을 실행하게된다. 그리고 node(노드1)을 neighbor(노드2)의 부모라고 저장하고 neighbor(노드2)를 node로 정해서 DFS탐색(재귀)를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;node = 2이고, 인접한 노드는 [1], 노드1만 있다. 그리고 node(노드2)는 탐색되었다고 저장한다.(visited[2] = 1) node(노드2)에 대한 새로운 neighbor를 정한다. 인접한 노드는 노드1 뿐이므로 neighbor = 1이 될 것이다. neighbor(노드1)은 이전에 탐색되었으므로(visited[1] = 1) if문을 실행하지 않고 끝낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝났으므로 다시 node = 1로 돌아온다. 그리고 neighbor = 3(노드3)이 된다. 똑같은 과정을 반복하고 노드3의 부모는 노드1로 저장되고 끝날것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 .. 나와 인접한 노드가 이미 방문된 적이 있다면, 내 부모임을 뜻한다. 그리고 나와 인접한 노드가 방문되지 않았다면 내 자식임을 뜻한다. preoder가 노드를 방문하고 좌, 우를 방문하는 방식이기 때문이다. inorder나 postorder로 코드를 짜면 방문한 순서가 달라질 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리를 활용한 첫 번째 문제였는데, 개념을 알아서 어렵지않게 풀 수 있었다. C의 구조체로 트리를 직접 만들고 다양한 탐색을 해 본 적은 있지만, java의 list로 만드는건 처음이었다. 그리고 훨씬 편리하다는걸 느꼈다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 전체 코드이다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class BOJ11725 {
    public static void addEdge(List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; graph, int u, int v) {
        // 무방향 그래프이므로 양방향 추가
        graph.get(u).add(v);
        graph.get(v).add(u);
    }

    public static void DFS(int[] parentArr, int[] visited, List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; graph, int node){
        // preoder 방식
        visited[node] = 1;

        for(int neighbor : graph.get(node)){ // node와 인접한 노드(neighbor) 탐색하기
            if(visited[neighbor] == 0){ // 탐색되지 않았다면
                parentArr[neighbor] = node; // neighbor는 node의 자식임
                DFS(parentArr, visited, graph, neighbor); // neighbor를 node로해서 재귀 탐색
            }
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N, i;
        StringTokenizer st;

        N = Integer.parseInt(br.readLine());
        List&amp;lt;List&amp;lt;Integer&amp;gt;&amp;gt; graph = new ArrayList&amp;lt;&amp;gt;();
        int[] parentArr = new int[N + 1];
        int[] visited = new int[N + 1];

        // 그래프에 노드 추가 -&amp;gt; 0번은 사용하지 않음
        for(i=0;i&amp;lt;=N;i++)
            graph.add(new ArrayList&amp;lt;&amp;gt;());

        // 노드에 간선 추가
        for(i=0;i&amp;lt;N-1;i++){
            st = new StringTokenizer(br.readLine());
            addEdge(graph, Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
        }

        // DFS -&amp;gt; preoder 로 부모 탐색
        DFS(parentArr, visited, graph, 1);

        // 0번째 노드와 루트는 제외하고 출력
        for(i=2;i&amp;lt;=N;i++)
            System.out.println(parentArr[i]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩가딩가</category>
      <category>dfs</category>
      <category>graph</category>
      <category>Java</category>
      <category>preorder</category>
      <category>Tree</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/87</guid>
      <comments>https://noooodlefts.tistory.com/87#entry87comment</comments>
      <pubDate>Sun, 8 Sep 2024 19:41:08 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 15657, N과 M (8)</title>
      <link>https://noooodlefts.tistory.com/86</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H6Ef1/btsJudaKxc0/9kLbjbgLiezAthyQoMGngK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H6Ef1/btsJudaKxc0/9kLbjbgLiezAthyQoMGngK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H6Ef1/btsJudaKxc0/9kLbjbgLiezAthyQoMGngK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH6Ef1%2FbtsJudaKxc0%2F9kLbjbgLiezAthyQoMGngK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1159&quot; height=&quot;549&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복가능, 비내림차순 = 오름차순 --&amp;gt; 중복 조합이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;1. 메인 --&amp;gt; 입력받고 오름차순 정렬함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;2. printSequence 함수&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public static void printSequence(int[] arr, int[] result, int N, int M, int toPick){
    int i, lastIdx, smallest;

    // base case -&amp;gt; 다 뽑았을때
    if (toPick == 0){
        for(i=0;i&amp;lt;M;i++)
            System.out.print(arr[result[i]] + &quot; &quot;);
        System.out.println();
        return;
    }

    // 결과배열의 idx, 초기에는 -1
    lastIdx = M - toPick - 1;

    // 반복문 돌릴때 i의 최소값 정하기
    if(toPick == M)
        smallest = 0;
    else
        smallest = result[lastIdx]; // 중복선택 가능하게 최솟값 변경

    // recursive case
    for(i=smallest;i&amp;lt;N;i++){
        result[lastIdx + 1] = i;
        printSequence(arr, result, N, M, toPick - 1);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;lastIdx : 결과 배열(result)의 인덱스 번호&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;smallest : 오름차순 정렬을 위해 사용한다. 단, 중복선택이 가능해야 하므로 최솟값을 마지막에 선택한 값 그 자체로 설정한다. 예를 들면, 마지막으로 저장한 수가 'result[0] = 1'이면, 다음으로 선택 가능한 수들 중에 제일 작은 수는 '1'이다. (조합일땐 +1을 해줘야함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;base case설명은 생략.. 앞이랑 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;recursive case에서 조합문제(15655번)과 다른점은 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복조합과 조합의 차이는 당연하지만 중복이 되지않는다는거다. 조합에서는 중복이 되지 않도록 smallest를 '마지막으로 선택한 값 +1'로 정해주고, 중복조합은 마지막에 '선택한 값' 그 자체로 정한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 전체 코드이다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

// 중복조합
public class BOJ15657 {
    public static void printSequence(int[] arr, int[] result, int N, int M, int toPick){
        int i, lastIdx, smallest;

        // base case -&amp;gt; 다 뽑았을때
        if (toPick == 0){
            for(i=0;i&amp;lt;M;i++)
                System.out.print(arr[result[i]] + &quot; &quot;);
            System.out.println();
            return;
        }

        // 결과배열의 idx, 초기에는 -1
        lastIdx = M - toPick - 1;

        // 반복문 돌릴때 i의 최소값 정하기
        if(toPick == M)
            smallest = 0;
        else
            smallest = result[lastIdx]; // 중복선택 가능하게 최솟값 변경

        // recursive case
        for(i=smallest;i&amp;lt;N;i++){
            result[lastIdx + 1] = i;
            printSequence(arr, result, N, M, toPick - 1);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N, M, i;
        int[] arr, result;
        StringTokenizer st;

        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        arr = new int[N];
        result = new int[M];

        // 입력
        st = new StringTokenizer(br.readLine());
        for(i=0;i&amp;lt;N;i++)
            arr[i] = Integer.parseInt(st.nextToken());

        Arrays.sort(arr); // 정렬
        printSequence(arr, result, N, M, M);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩가딩가</category>
      <category>combinationwithrepetion</category>
      <category>Java</category>
      <category>recursion</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/86</guid>
      <comments>https://noooodlefts.tistory.com/86#entry86comment</comments>
      <pubDate>Fri, 6 Sep 2024 20:38:19 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 15656, N과 M (7)</title>
      <link>https://noooodlefts.tistory.com/85</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;489&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kKMmo/btsJt1aByZG/YEBay21GeDPxb3cfRPuWPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kKMmo/btsJt1aByZG/YEBay21GeDPxb3cfRPuWPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kKMmo/btsJt1aByZG/YEBay21GeDPxb3cfRPuWPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkKMmo%2FbtsJt1aByZG%2FYEBay21GeDPxb3cfRPuWPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1159&quot; height=&quot;489&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;489&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오름차순이어야 한다는 조건이 없으니 이건 중복 순열 문제이다. 그냥 순열(백준 15654번)과 비슷한데, 중복체크하는 것만 빼면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1. 메인 --&amp;gt; 입력받고 오름차순 정렬함&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2. printSequence 함수&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public static void printSequence(int[] arr, int[] result, int N, int M, int toPick, StringBuilder sb){
    int i, lastIdx;

    // base case -&amp;gt; 다 뽑았을때
    if (toPick == 0){
        for(i=0;i&amp;lt;M;i++)
            sb.append(arr[result[i]]).append(' ');
        sb.append('\n');
        return;
    }

    // 결과배열의 idx, 초기에는 -1
    lastIdx = M - toPick - 1;

    // recursive case 
    for(i=0;i&amp;lt;N;i++){
        result[lastIdx + 1] = i; // 중복 체크를 하지 않음
        printSequence(arr, result, N, M, toPick - 1, sb);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;lastIdx : 결과 배열(result)의 인덱스 번호&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;오름차순 정렬이 필요하지 않으니 smallest는 정의하지 않았다.(i는 0부터 시작..)&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #222222; text-align: start;&quot;&gt;base case는 앞선 15654번, 15655번과 같다. 출력한다.. 근데 result배열에는 arr의 인덱스를 저장한것이므로 arr[result[ ]] 형식으로 출력해야한다. 아 그리고 그냥 출력했더니 시간초과나서 StringBulider로 출력했다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;recursive case는 중복체크를 하지 않으므로(1 1, 1 7 ... 가능) 전부 다 2개씩 선택한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 전체 코드이다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

// 중복순열
public class BOJ15656 {
    public static void printSequence(int[] arr, int[] result, int N, int M, int toPick, StringBuilder sb){
        int i, lastIdx;

        // base case -&amp;gt; 다 뽑았을때
        if (toPick == 0){
            for(i=0;i&amp;lt;M;i++)
                sb.append(arr[result[i]]).append(' ');
            sb.append('\n');
            return;
        }

        // 결과배열의 idx, 초기에는 -1
        lastIdx = M - toPick - 1;

        // recursive case 
        for(i=0;i&amp;lt;N;i++){
            result[lastIdx + 1] = i; // 중복 체크를 하지 않음
            printSequence(arr, result, N, M, toPick - 1, sb);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N, M, i;
        int[] arr, result;
        StringTokenizer st;
        StringBuilder sb = new StringBuilder();

        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        arr = new int[N];
        result = new int[M];

        // 입력
        st = new StringTokenizer(br.readLine());
        for(i=0;i&amp;lt;N;i++)
            arr[i] = Integer.parseInt(st.nextToken());

        Arrays.sort(arr); // 정렬
        printSequence(arr, result, N, M, M, sb);
        System.out.println(sb);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩가딩가</category>
      <category>Java</category>
      <category>permutationwithrepetition</category>
      <category>recursion</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/85</guid>
      <comments>https://noooodlefts.tistory.com/85#entry85comment</comments>
      <pubDate>Fri, 6 Sep 2024 20:31:39 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 15655, N과 M (6)</title>
      <link>https://noooodlefts.tistory.com/84</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HbZTG/btsJs6DsCWI/alCc2K2OehZZlnvHqJ8qbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HbZTG/btsJs6DsCWI/alCc2K2OehZZlnvHqJ8qbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HbZTG/btsJs6DsCWI/alCc2K2OehZZlnvHqJ8qbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHbZTG%2FbtsJs6DsCWI%2FalCc2K2OehZZlnvHqJ8qbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1157&quot; height=&quot;488&quot; data-origin-width=&quot;1157&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 조합이다. 조합은 순서에 상관없이 N개에서 M개를 선택하는 수열이다. 1 7과 7 1은 같은 수열이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 메인 --&amp;gt; 입력받고 오름차순 정렬함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. printSequence 함수&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public static void printSequence(int[] arr, int[] result, int N, int M, int toPick){
    int i, lastIdx, smallest;

    // base case -&amp;gt; 다 뽑았을때
    if (toPick == 0){
        for(i=0;i&amp;lt;M;i++)
            System.out.print(arr[result[i]] + &quot; &quot;);
        System.out.println();
        return;
    }

    // 결과배열의 idx, 초기에는 -1
    lastIdx = M - toPick - 1;

    // 반복문 돌릴때 i의 최소값 정하기
    if(toPick == M)
        smallest = 0;
    else
        smallest = result[lastIdx] + 1;

    // recursive case
    for(i=smallest;i&amp;lt;N;i++){
        result[lastIdx + 1] = i;
        printSequence(arr, result, N, M, toPick - 1);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lastIdx : 결과 배열(result)의 인덱스 번호&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;smallest : 오름차순 정렬을 위해 사용하는데, 지금까지 선택한 수들보다 큰 수들중에 제일 작은 값을 저장한다. 예를 들면 마지막으로 저장한 수가 result[0] = 1이면, 중복없이 뽑기 위해 smallest = result[0] + 1 = 2을 저장한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;base case는 앞선 15654번과 같다. 출력한다.. 근데 result배열에는 arr의 인덱스를 저장한것이므로 arr[result[ ]] 형식으로 출력해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;recursive case는 조금 다르다. recursive case를 실행하기 전에 smallest를 설정한다. 지금까지 선택한 값이 없으면(이번이 첫번째 선택) smallest = 0이다. 이전에 선택한 적이 있다면 마지막으로 저장한 수보다 + 1 을해 저장한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 반복문을 실행한다. 이는 오름차순으로 중복없이 정렬하기위해 설정된 값이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

// 조합
public class BOJ15655 {
    public static void printSequence(int[] arr, int[] result, int N, int M, int toPick){
        int i, lastIdx, smallest;

        // base case -&amp;gt; 다 뽑았을때
        if (toPick == 0){
            for(i=0;i&amp;lt;M;i++)
                System.out.print(arr[result[i]] + &quot; &quot;);
            System.out.println();
            return;
        }

        // 결과배열의 idx, 초기에는 -1
        lastIdx = M - toPick - 1;

        // 반복문 돌릴때 i의 최소값 정하기
        if(toPick == M)
            smallest = 0;
        else
            smallest = result[lastIdx] + 1;

        // recursive case
        for(i=smallest;i&amp;lt;N;i++){
            result[lastIdx + 1] = i;
            printSequence(arr, result, N, M, toPick - 1);
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N, M, i;
        int[] arr, result;
        StringTokenizer st;

        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        arr = new int[N];
        result = new int[M];

        // 입력
        st = new StringTokenizer(br.readLine());
        for(i=0;i&amp;lt;N;i++)
            arr[i] = Integer.parseInt(st.nextToken());

        Arrays.sort(arr); // 정렬
        printSequence(arr, result, N, M, M);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩가딩가</category>
      <category>Combination</category>
      <category>Java</category>
      <category>recursion</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/84</guid>
      <comments>https://noooodlefts.tistory.com/84#entry84comment</comments>
      <pubDate>Fri, 6 Sep 2024 17:12:08 +0900</pubDate>
    </item>
    <item>
      <title>[JAVA]BOJ 15654, N과 M (5)</title>
      <link>https://noooodlefts.tistory.com/83</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biPaUY/btsJt7H5RBs/VYshftNWaNSpVVg28kgP6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biPaUY/btsJt7H5RBs/VYshftNWaNSpVVg28kgP6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biPaUY/btsJt7H5RBs/VYshftNWaNSpVVg28kgP6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiPaUY%2FbtsJt7H5RBs%2FVYshftNWaNSpVVg28kgP6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1160&quot; height=&quot;462&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N에서 중복이 되지않게 M개를 고른다. 그리고 예제를 보니 1 7 과 7 1 은 다른 수열로 친다.. 즉 순서 따진다는거고 이는 '순열'을 뜻한다. 순열 문제이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순열은 순서를 고려하고 중복을 허용하지 않는 수열이다. 문제를 더 설명할건 없어서 바로 코드 설명으로 넘어가자.. 재귀를 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 메인&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    int N, M, i;
    int[] arr, result;
    StringTokenizer st;

    st = new StringTokenizer(br.readLine());
    N = Integer.parseInt(st.nextToken());
    M = Integer.parseInt(st.nextToken());
    arr = new int[N];
    result = new int[M];

    // 입력
    st = new StringTokenizer(br.readLine());
    for(i=0;i&amp;lt;N;i++)
        arr[i] = Integer.parseInt(st.nextToken());

    Arrays.sort(arr); // 정렬
    printSequence(arr, result, N, M, M);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 필드에 대해 입력을 받는다. 그리고 오름차순으로 출력해야 하므로 정렬을 해주었다. printSequence가 수열을 출력하는 함수이다. 매개변수 각각 (원래 배열, 결과배열, 숫자의개수, 뽑을숫자의 개수, 앞으로뽑을 숫자의개수)가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. printSequence 함수&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    public static void printSequence(int[] arr, int[] result, int N, int M, int toPick){
        int i, lastIdx;

        // base case -&amp;gt; 다 뽑았을때
        if (toPick == 0){
            for(i=0;i&amp;lt;M;i++)
                System.out.print(arr[result[i]] + &quot; &quot;);
            System.out.println();
            return;
        }

        // 결과배열의 idx, 초기에는 -1
        lastIdx = M - toPick - 1;

        // recursive case
        for(i=0;i&amp;lt;N;i++){
            if(checkRepetition(result, i, lastIdx) == 1){ // 중복 허용 X
                result[lastIdx + 1] = i;
                printSequence(arr, result, N, M, toPick - 1);
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 변수 설명부터 하자면.. lastIdx는 result배열에 저장할때 결과를 저장하는 result배열의 인덱스값이다. toPick은 앞으로 뽑을 값.. 그러니까 7개중에 3개를 뽑는다면, 처음에는 앞으로 3개를 뽑아야 한다. 한 번 뽑고나면 앞으로 2개만 뽑으면 된다. 그걸 뜻하는 변수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;base case : N개중에 M개를 다 선택했을때는 출력하고 끝낸다. 선택할때 arr[ ] 의 인덱스를 선택해서 result배열에 저장하므로, 출력을 arr[result[ ]] &amp;lt;- 이런식으로 해야 원하는 값이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;recursive case : 반복문을 사용해서 실제로 뽑는다. result배열 안에 이번 차례의 값(i)가 없을때만 result배열에 값을 저장한다. 저장시에는 마지막으로 저장한 위치(lastIdx) 다음에 저장한다. 그리고 하나 뽑았으니 앞으로 뽑을 값(toPick)을 감소시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. result 배열의 중복을 확인하는 함수&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    public static int checkRepetition(int[] result, int N, int lastIdx){ // 중복을 확인하는 함수
        int i;

        for(i=0;i&amp;lt;=lastIdx;i++){
            if(result[i] == N)
                return 0;
        }
        return 1;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 선택한 값들 중에서 이번에 넣을 값(N)이 있는지 없는지 확인하면 되므로 lastIdx까지만 확인한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 전체 코드이다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

// 순열
public class BOJ15654 {
    public static int checkRepetition(int[] result, int N, int lastIdx){ // 중복을 확인하는 함수
        int i;

        for(i=0;i&amp;lt;=lastIdx;i++){
            if(result[i] == N)
                return 0;
        }
        return 1;
    }

    public static void printSequence(int[] arr, int[] result, int N, int M, int toPick){
        int i, lastIdx;

        // base case -&amp;gt; 다 뽑았을때
        if (toPick == 0){
            for(i=0;i&amp;lt;M;i++)
                System.out.print(arr[result[i]] + &quot; &quot;);
            System.out.println();
            return;
        }

        // 결과배열의 idx, 초기에는 -1
        lastIdx = M - toPick - 1;

        // recursive case
        for(i=0;i&amp;lt;N;i++){
            if(checkRepetition(result, i, lastIdx) == 1){ // 중복 허용 X
                result[lastIdx + 1] = i;
                printSequence(arr, result, N, M, toPick - 1);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N, M, i;
        int[] arr, result;
        StringTokenizer st;

        st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        arr = new int[N];
        result = new int[M];

        // 입력
        st = new StringTokenizer(br.readLine());
        for(i=0;i&amp;lt;N;i++)
            arr[i] = Integer.parseInt(st.nextToken());

        Arrays.sort(arr); // 정렬
        printSequence(arr, result, N, M, M);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩가딩가</category>
      <category>Java</category>
      <category>permutation</category>
      <category>recursion</category>
      <author>Noooodle</author>
      <guid isPermaLink="true">https://noooodlefts.tistory.com/83</guid>
      <comments>https://noooodlefts.tistory.com/83#entry83comment</comments>
      <pubDate>Fri, 6 Sep 2024 17:01:53 +0900</pubDate>
    </item>
  </channel>
</rss>