<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>devlog</title>
    <link>https://salmon16.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 5 Jul 2026 05:53:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>salmon16</managingEditor>
    <item>
      <title>[백준] 수영장 만들기 1113번 (java)</title>
      <link>https://salmon16.tistory.com/294</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/1113&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1113&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경계를 판단하기가 어려웠고 높이가 1~9이기 때문에 범위가 매우 작다는 점을 이용해서 가장 작은 높이에서 가장 큰 높이 직전까지 1씩 증가해 가면서 풀이하는 방법으로 풀이했다.&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;테두리일 경우, 넘쳐나게 되므로 테두리일 땐, 높이를 증가시키면 안 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 visited 값을 2로 설정한 것은 높이를 증가시키지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 중복해서 더해지는 경우도 방지해야 하므로 한 번 높이를 증가시킨 경우 visited값을 +1을 해주어서 중복 계산을 방지해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1750142883962&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;


public class Main {
    static int n, m;
    static int[][] pool, visited;
    static int maxN, minN, ans = 0;
    static int[] dy = {0, 0, 1, -1};
    static int[] dx = {1, -1, 0, 0};
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        m = Integer.parseInt(st.nextToken());
        pool = new int[n][m];
        visited = new int[n][m];
        maxN = 0;
        minN = 9;
        for (int i = 0; i &amp;lt; n; i++) {
            String str = br.readLine();
            for (int j = 0;j &amp;lt; str.length();j++) {
                pool[i][j] = str.charAt(j) - '0';
                maxN = Math.max(maxN, pool[i][j]);
                minN = Math.min(minN, pool[i][j]);
            }
        }
        // 각 수에서 bfs를 돌리며, 채울 수 있는지 없는지 판별한다 수가 된다면 큐에 넣고 bfs 만약 돌다 끝에 닿으면 다 패기한다.
        for (int i = minN; i &amp;lt; maxN; i++) {
            // visited 초기화 하기
            initViisted();
            for (int j = 1; j &amp;lt; n-1; j++) {
                for (int k = 1; k &amp;lt; m-1; k++) {
                    if (visited[j][k] != 0) continue;
                    if (pool[j][k] != i) continue; // i가 아니면 패스
                    bfs(j, k, i);
                }
            }
        }
        System.out.println(ans);
    }
    public static void bfs(int y, int x, int h) {
        Queue&amp;lt;int[]&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
        q.offer(new int[] {y, x});
        visited[y][x] = 1;
        boolean flag = true;
        while(!q.isEmpty()) {
            int[] cur = q.poll();
            for (int i = 0;i &amp;lt; 4;i++) {
                int ny = cur[0] + dy[i];
                int nx = cur[1] + dx[i];
                if (ny &amp;lt; 0 || ny &amp;gt;= n || nx &amp;lt; 0 || nx &amp;gt;= m) continue;
                if (visited[ny][nx] == 1) continue;
                if (pool[ny][nx] &amp;lt; h) flag = false;
                // 테두리라면 종료해야한다.
                if ((ny == 0 || nx == 0 || ny == n-1 || nx == m-1) &amp;amp;&amp;amp; pool[ny][nx] &amp;lt;= h) {
                    flag = false;
                    continue;
                }
                // 주변에 나보다 작은 것이 있지만 처리가 되지 않은 것이 있다면 종료해야한다.
                if (pool[ny][nx] != h) continue;
                q.offer(new int[] {ny, nx});
                visited[ny][nx] = 1;
            }
        }
        if (flag) {
            for (int i = 0; i &amp;lt; n; i++) {
                for (int j = 0; j &amp;lt; m; j++) {
                    if (visited[i][j] == 1) {
                        pool[i][j]++;
                        ans++;
                        visited[i][j]++; // 중복해서 더해지지 않도록 하는 함수
                    }
                }
            }
        }
        else { // flag가 false일 때
            for (int i = 0; i &amp;lt; n; i++) {
                for (int j = 0; j &amp;lt; m; j++) {
                    if (visited[i][j] == 1) {
                        visited[i][j] = 2;
                    }
                }
            }
        }
        return ;
    }
    public static void initViisted() {
        for (int i = 0; i &amp;lt; n; i++) {
            Arrays.fill(visited[i], 0);
        }
    }

}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/294</guid>
      <comments>https://salmon16.tistory.com/294#entry294comment</comments>
      <pubDate>Tue, 17 Jun 2025 15:49:18 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 외판원 순회 2098번 (java) 비트마스킹 + dp</title>
      <link>https://salmon16.tistory.com/293</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/2098&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/2098&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외판원 문제를 비트마스킹과 DP를 활용해서 풀이하는 문제이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DP를 2차원 배열로 선언한 후 dp[y][x] = y를 현재 지점 x를 현재 지점을 포함한 방문한 노드의 인덱스를 비트로 변경했을 때 값으로 설정한다.&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;ex 11001(2진수) -&amp;gt; 1, 4, 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;모든 지점을 방문했을 경우는 (1 &amp;lt;&amp;lt; n) -1 이 된다 -&amp;gt; 011111 = 100000 - 1 (2진수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같은 코드를 통해 i번 인덱스를 방문했는지 판단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if((visited &amp;amp; (1 &amp;lt;&amp;lt; i)) &amp;gt; 0) continue;&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;이후에는 일반적인 dp문제와 동일하게 풀이하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1749965570629&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;


public class Main {

    static int n;
    static int[][] W;
    static int[][] dp;
    static int ans;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        n = Integer.parseInt(br.readLine());
        W = new int[n][n];
        dp = new int[n][1 &amp;lt;&amp;lt; n];
        for (int i = 0; i &amp;lt; n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j &amp;lt; n; j++) {
                W[i][j] = Integer.parseInt(st.nextToken());
            }
            Arrays.fill(dp[i], -1);
        }
        System.out.println(dfs(0, 1));
    }

    static int dfs(int idx, int visited) { // 현재 idx이고 지금까지 방문한 것이 visited이다.
        if (visited == (1 &amp;lt;&amp;lt; n) - 1) { //모든 지점 방문했을 때
            if (W[idx][0] == 0) return 987654321;  // 돌아갈 수 없으면 큰 값 반환
            return W[idx][0];
        }
        if(dp[idx][visited] != -1) {
            return dp[idx][visited];
        }
        int ret = 987654321;
        for (int i = 0 ;i &amp;lt; n;i++) {
            if((visited &amp;amp; (1 &amp;lt;&amp;lt; i)) &amp;gt; 0) continue;
            if (W[idx][i] == 0) continue;
            ret = Math.min(ret, dfs(i, visited | (1 &amp;lt;&amp;lt; i)) + W[idx][i]);
        }
        dp[idx][visited] = ret;
        return ret;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/293</guid>
      <comments>https://salmon16.tistory.com/293#entry293comment</comments>
      <pubDate>Sun, 15 Jun 2025 14:32:59 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 우주 탐사선 17182번 (java) 플로이드 워샬, 순열</title>
      <link>https://salmon16.tistory.com/292</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/17182&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/17182&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순열 문제라는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n이 10까지 밖에 되지 않으므로 방문할 순서를 정하고 최소를 구하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 순열만 사용해서 구해도 되지만 플로이드 워샬을 사용해 보고 싶어서 사용해 보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1749957145343&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.nio.Buffer;
import java.util.*;


public class Main {

    static int n,k, ans;
    static int[][] dist;
    static boolean[] visited;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());
        ans = Integer.MAX_VALUE;
        dist = new int[n][n];
        visited = new boolean[n];
        for (int i = 0; i &amp;lt; n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j &amp;lt; n; j++) {
                dist[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        // 플로이드 와샬 알고리즘
        for (int i = 0;i &amp;lt; n;i++) {
            for (int j = 0;j &amp;lt; n;j++) {
                for (int z = 0;z &amp;lt; n;z++) {
                    dist[i][j] = Math.min(dist[i][z] + dist[z][j], dist[i][j]);
                }
            }
        }

        // 순열 하기
        visited[k] = true;
        dfs(k, 1, 0);
        System.out.println(ans);
    }

    public static void dfs(int cur, int cnt, int cost) {
        if (cnt == n) {
            ans = Math.min(ans, cost);
            return ;
        }
        for (int i = 0; i &amp;lt; n; i++) {
            if (visited[i]) continue;
            visited[i] = true;
            dfs(i, cnt + 1, cost + dist[cur][i]);
            visited[i] = false;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/292</guid>
      <comments>https://salmon16.tistory.com/292#entry292comment</comments>
      <pubDate>Sun, 15 Jun 2025 12:12:34 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 닭싸움 팀 정하기 1765번 Java</title>
      <link>https://salmon16.tistory.com/291</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/1765&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1765&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니온 파인드 문제이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 F인 친구가 나오게 된다면, union을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 E가 나오게 된다면 enemy에 저장을 한 후, 모든 enemy를 돌며 enemy의 enemy를 union을 해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 집합의 수를 Set을 활용하여 세었다.&lt;/p&gt;
&lt;pre id=&quot;code_1749811703004&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;
import java.lang.*;
import java.io.*;

// The main method must be in a class named &quot;Main&quot;.
class Main {
    static int n, m;
    static int[] parents;
    static ArrayList&amp;lt;Integer&amp;gt;[] enemy;

    static int find(int a) {
        if (parents[a] == a) return a;
        parents[a] = find(parents[a]);
        return parents[a];
    }
    static void union(int a, int b) {
        int parA = find(a);
        int parB = find(b);
        if (parA != parB) {
            if (parA &amp;lt; parB) {
                parents[parB] = parA;
            }
            else {
                parents[parA] = parB;
            }
        }
        return;
        
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        n = Integer.parseInt(br.readLine());
        m = Integer.parseInt(br.readLine());
        parents = new int[n+1];
        enemy = new ArrayList[n+1];
        for (int i = 0;i &amp;lt;= n;i++) {
            parents[i] = i;
            enemy[i] = new ArrayList&amp;lt;&amp;gt;();
        }
        for (int i = 0;i &amp;lt; m;i++) {
            st = new StringTokenizer(br.readLine());
            if (st.nextToken().equals(&quot;F&quot;)) {
                union(Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken()));
            }
            else {
                int a = Integer.parseInt(st.nextToken());
                int b = Integer.parseInt(st.nextToken());
                enemy[a].add(b);
                enemy[b].add(a);
                
            }
        }

        for (int i = 1;i &amp;lt;= n;i++) {
            for (int k = 0;k &amp;lt; enemy[i].size();k++) {
                int enemyIdx = enemy[i].get(k);
                for (int j = 0;j &amp;lt; enemy[enemyIdx].size();j++) {
                    union(i, enemy[enemyIdx].get(j));
                }
            }
        }

        Set&amp;lt;Integer&amp;gt; ans = new HashSet&amp;lt;&amp;gt;();

        for (int i = 1;i &amp;lt;= n; i++) {
            find(i);            
            ans.add(parents[i]);
        }
        
        System.out.println(ans.size());
        return ;       
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/291</guid>
      <comments>https://salmon16.tistory.com/291#entry291comment</comments>
      <pubDate>Fri, 13 Jun 2025 19:48:29 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 홀짝트리 (java) 그래프</title>
      <link>https://salmon16.tistory.com/290</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/388354?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/388354?language=java&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1749211982173&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/388354?language=java&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7sIvc/hyY5cTRE8J/JN0TNKEIOH3KWafNQ9Dowk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bsMDlk/hyY31ZtDsY/ksrHFE2iaaKXFUKeuoKNMK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/388354?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/388354?language=java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7sIvc/hyY5cTRE8J/JN0TNKEIOH3KWafNQ9Dowk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bsMDlk/hyY31ZtDsY/ksrHFE2iaaKXFUKeuoKNMK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&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;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 모든 노드를 루투로 설정하고 싹 다 계산하려고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 시간 복잡도가 10^6 * 10^6 으로 시간이 복잡도를 만족하지 못한다.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서 가장 중요한 부분은 어떤 노드를 루트로 잡느냐였고, 해당 노드가 (루트 -&amp;gt; 루트 아님), (루트 아님 -&amp;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;이런 특징을 바탕으로 모든 노드가 짝홀 트리이거나 역짝홀 트리가 되려면, 모든 노드가 루트가 아니라고 가정하고 푼 이후에 단 한 노드만 짝홀 트리이거나 역짝홀 트리이면 해당 노드를 루트로 변경하게 된다면, 짝홀 트리 또는 역짝홀 트리가 된다.&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_1749372710722&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;
import java.io.*;

class Solution {
    
    public static HashMap&amp;lt;Integer, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph = new HashMap&amp;lt;&amp;gt;();
    public static HashMap&amp;lt;Integer, Boolean&amp;gt; visited = new HashMap&amp;lt;&amp;gt;();
    public static int[] answer = {0, 0};
    
    public static void bfs(int node) {
        Queue&amp;lt;Integer&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
        int A = 0, B = 0; // 짝홀수 노드, 역짝홀수 노드
        q.add(node);
                
        while(!q.isEmpty()) {
            int cur = q.poll();
            ArrayList&amp;lt;Integer&amp;gt; edge = graph.get(cur);
            if ((cur % 2) != ((edge.size() + 1) % 2)) B++;
            else A++;
            
            for (int i = 0; i &amp;lt; edge.size();i++) {
                if (visited.get(edge.get(i)) == false) {
                    visited.put(edge.get(i), true);
                    q.add(edge.get(i));
                }
            }            
        }
        
        if (A == 1) {
            answer[1]++;
        }
        if (B == 1) {
            answer[0]++;
        }
        
    }
    public int[] solution(int[] nodes, int[][] edges) {        
        
        
        for (int i = 0;i &amp;lt; nodes.length;i++) {
            graph.put(nodes[i], new ArrayList&amp;lt;&amp;gt;());
            visited.put(nodes[i], false);
        }
        
        for (int i = 0;i &amp;lt; edges.length;i++) { // 그래프 만들기
            int a = edges[i][0];
            int b = edges[i][1];            
            graph.get(a).add(b);
            graph.get(b).add(a);
        }
        // 모든 노드가 루트가 아니라고 가정하고, 구하기
        
        for(int i = 0;i &amp;lt; nodes.length;i++) {
            if (visited.get(nodes[i]) == false) {
                visited.put(nodes[i], true);
                bfs(nodes[i]);
            }
        }
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/290</guid>
      <comments>https://salmon16.tistory.com/290#entry290comment</comments>
      <pubDate>Sun, 8 Jun 2025 17:51:56 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 불켜기 11967번 (java)</title>
      <link>https://salmon16.tistory.com/289</link>
      <description>&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;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/11967&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11967&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&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;p data-ke-size=&quot;size16&quot;&gt;불을 켤 때, 주변에 방문한 곳이 있다면 해당 방도 방문할 수 있기 때문에 queue에 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 방에 방문했을 때, 주변에 방문을 하지 않았지만, 불이 켜진 방이 있다면 해당 방도 queue에 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1749358873665&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;
import java.lang.*;
import java.io.*;

public class Main {    

    public static ArrayList&amp;lt;int[]&amp;gt;[][] switches;
    public static boolean[][] visited;
    public static boolean[][] onLight;

    public static int[] dy = {0, 0, -1, 1};
    public static int[] dx = {1, -1, 0, 0};
    public static int N, ans = 1;
    public static void bfs() {
        Queue&amp;lt;int[]&amp;gt; q = new LinkedList&amp;lt;&amp;gt;();
        q.add(new int[] {0, 0});
        visited[0][0] = true;
        onLight[0][0] = true;
        while(!q.isEmpty()) {
            int[] cur = q.poll();
            
            // 방문 했을 때 불 다 켜기
            for (int i = 0;i &amp;lt; switches[cur[0]][cur[1]].size();i++) { 
                int[] light = switches[cur[0]][cur[1]].get(i);
                if (onLight[light[0]][light[1]] == false) ans++;
                onLight[light[0]][light[1]] = true;
                if (visited[light[0]][light[1]]) continue;
                for (int k = 0;k &amp;lt; 4;k++) {
                    int ny = light[0] + dy[k];
                    int nx = light[1] + dx[k];
                    if (ny &amp;lt; 0 || ny &amp;gt;= N || nx &amp;lt; 0 || nx &amp;gt;= N) continue;
                    if (visited[ny][nx] == true) {
                        q.add(new int[] {light[0], light[1]});                        
                        visited[light[0]][light[1]] = true;
                    } 
                }
            }
            
            for (int i = 0;i &amp;lt; 4;i++) {
                int ny = cur[0] + dy[i];
                int nx = cur[1] + dx[i];
                if (ny &amp;lt; 0 || ny &amp;gt;= N || nx &amp;lt; 0 || nx &amp;gt;= N) continue;
                if (visited[ny][nx]) continue;
                if (!onLight[ny][nx]) continue;
                q.add(new int[] {ny, nx});
                visited[ny][nx] = true;                
            }
            
        }
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // 첫 줄 입력: N, M
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        visited = new boolean[N][N];
        onLight = new boolean[N][N];
        // 스위치 정보 저장
        switches = new ArrayList[N][N];
        for (int i = 0; i &amp;lt; N; i++) {
            for (int j = 0; j &amp;lt; N; j++) {
                switches[i][j] = new ArrayList&amp;lt;&amp;gt;();
            }
        }

        // 다음 M줄 입력
        for (int i = 0; i &amp;lt; M; i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());

            switches[y-1][x-1].add(new int[]{b-1, a-1});
        }

        bfs();

        System.out.println(ans);
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/289</guid>
      <comments>https://salmon16.tistory.com/289#entry289comment</comments>
      <pubDate>Sun, 8 Jun 2025 14:01:21 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 당근 훔쳐 먹기 18234번 (c++)</title>
      <link>https://salmon16.tistory.com/288</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/18234&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/18234&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pi는 wi보다 항상 크다.라는 조건에 의해 그리디로 풀이할 수 있음을 파악했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pi는 당근을 뽑지 않으면 계속해서 누적되다가 해당 당근을 뽑게 된다면 누적된 pi와 wi만큼 맛을 얻을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 T일 전까지 가장 큰 pi를 계속 누적을 하다 마지막에 뽑는 것이 가장 많은 맛을 얻을 수 있다는 것을 알 수 있다.&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;또한 pi는 wi보다 항상 크다라는 조건에 의해, 만약 T가 6이고 당근이 3종류라면 6, 5, 4일 차에만 당근을 뽑아 먹고, 1, 2, 3일 차에는 당근을 안 뽑아 먹는 것이 더 크다는 조건을 알 수 있다.&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;(만약 뽑게 된다면, wi가 중간에 포함되어야 하기 때문에 안 뽑고 Pi만큼 얻는게 더 좋다.)&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;이렇게 풀이하기 위해 당근을 pi가 큰게 먼저 나오도록 정렬을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pi가 같다면 wi가 큰 것이 유리하기 때문에 wi가 큰 게 오도록 정렬&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;실수한 부분 정렬 함수를 아래와 같이 만들어야 잘 동작을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740979249602&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool cmp(const pair&amp;lt;int, int&amp;gt;&amp;amp; p1, const pair&amp;lt;int, int&amp;gt;&amp;amp; p2) {
    if (p1.second != p2.second) return p1.second &amp;gt; p2.second;  // 내림차순 정렬
    return p1.first &amp;gt; p2.first; // second가 같으면 first 기준 내림차순
}&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;아래와 같이 작성하게 된다면 p1.first == p2.first , p1.second == p2.second일 경우 에러가 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1740979338329&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool cmp(const pair&amp;lt;int, int&amp;gt;&amp;amp; p1, const pair&amp;lt;int, int&amp;gt;&amp;amp; p2) {
	if (p1.first &amp;lt; p2.first) return false;
    else if (p1.first == p2.first) {
    	if (p1.second &amp;lt; p2.second) return false;
        else return true;
    }
    else return true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1740979375120&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include&amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;

int n, t;
vector&amp;lt;pair&amp;lt;int, int&amp;gt; &amp;gt; wp;


int w[200001];
int p[200001];

bool cmp(const pair&amp;lt;int, int&amp;gt;&amp;amp; p1, const pair&amp;lt;int, int&amp;gt;&amp;amp; p2) {
    if (p1.second != p2.second) return p1.second &amp;gt; p2.second;  // 내림차순 정렬
    return p1.first &amp;gt; p2.first; // second가 같으면 first 기준 내림차순
}

int main() {

    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; t;

    int a, b;
    for (int i = 0;i &amp;lt; n;i++) {
        cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
        wp.push_back(make_pair(a, b));
    }

    sort(wp.begin(), wp.end(), cmp);

    long long ans = 0;
    int idx = min(t, n);
    for (int i = 0;i &amp;lt; idx;i++) {
        ans += (wp[i].first + wp[i].second * static_cast&amp;lt;long long&amp;gt;(t - i - 1));
    }
    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; endl;
    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/288</guid>
      <comments>https://salmon16.tistory.com/288#entry288comment</comments>
      <pubDate>Mon, 3 Mar 2025 14:23:05 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 통신망 분할 17398번 (c++) 순서 역으로 생각하기</title>
      <link>https://salmon16.tistory.com/287</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/17398&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/17398&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&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;간선을 하나씩 끊어 가면서 이때 나누어진 두 집합의 노드의 수를 계산하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 간선을 끊을 때마다, 끊어진 두 노드에서 bfs 또는 dfs를 수행해서 각 집합의 노드의 수를 계산하게 된다면 시간 복잡도가 초과된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 때문에 nlogn 이하의 시간 복잡도를 가지는 알고리즘을 생각해 내야 했다.&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;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. 순서를 역으로 생각해 보기&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;span&gt;&lt;b&gt;끊을 간선을 제외한 상태&lt;/b&gt;&lt;/span&gt;로 그래프를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span&gt;이제 &lt;/span&gt;&lt;b&gt;끊어진 간선을 하나씩 다시 연결하면서&lt;/b&gt;&lt;span&gt; 노드 개수를 계산한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. &lt;/span&gt;간선을 추가하기 &lt;span&gt;&lt;b&gt;전의 두 집합 크기&lt;/b&gt;&lt;/span&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&gt;&lt;b&gt;매번 BFS/DFS를 돌리지 않아도&lt;/b&gt;&lt;/span&gt; 각 집합의 크기를 빠르게 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740911658858&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;
vector&amp;lt;pair&amp;lt;int, int&amp;gt; &amp;gt; edge;
long long cnt[100001];
int visited[100001];
int parents[100001];
vector&amp;lt;int&amp;gt; orders;

int n, m, q;

int find(int a) {
    if (parents[a] == a) return a;

    parents[a] = find(parents[a]);
    return parents[a];
}

void union_node(int a, int b){
    int parents_a = find(a);
    int parents_b = find(b);

    if (parents_a == parents_b) return;
    if (parents_a &amp;lt; parents_b) {
        parents[parents_b] = parents_a;
        cnt[parents_a] += cnt[parents_b];
        cnt[parents_b] = 0;
    }

    else {
        parents[parents_a] = parents_b;
        cnt[parents_b] += cnt[parents_a];
        cnt[parents_a] = 0;
    }
}

int main() {

    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; m &amp;gt;&amp;gt; q;    

    int a, b;
    for (int i = 0;i &amp;lt; n;i++) {
        parents[i] = i;
        cnt[i] = 1;
    }
    for (int i = 0;i &amp;lt; m;i++) {
        cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
        edge.push_back(make_pair(a-1, b-1));
    }    
    for (int i = 0;i &amp;lt; q;i++) {
        cin &amp;gt;&amp;gt; a;
        visited[a-1] = 1; // 끊을 엣지
        orders.push_back(a-1);
    }

    for (int i = 0;i &amp;lt; m;i++) { //초기 다 묶기
        if (visited[i] == 1) continue;
        union_node(edge[i].first, edge[i].second);
    }
    long long ans = 0;    
    for (int i = q-1; i &amp;gt;= 0 ;i--) {
        int a = edge[orders[i]].first;
        int b = edge[orders[i]].second;        
        int parents_a = find(a);
        int parents_b = find(b);
        if (parents_a == parents_b) continue;
        ans += (cnt[parents_a] * cnt[parents_b]);
        union_node(a, b);        
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; endl;

    return 0;
}&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;&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>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/287</guid>
      <comments>https://salmon16.tistory.com/287#entry287comment</comments>
      <pubDate>Sun, 2 Mar 2025 19:34:45 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 중앙 트리 7812번 (java) 트리에서 dp</title>
      <link>https://salmon16.tistory.com/286</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/7812&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/7812&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 문제의 케이스가 여러 번 주어진다는 것을 보지 못하고 O(n^2)으로 풀이할 수 있어서 풀이했지만, 케이스가 여러 개 주어지므로 시간 초과가 발생한다.&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;즉 O(n)만에 풀이를 해야한다.&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;A가 중앙일 때와 B가 중앙일 때를 비교해 보면 A와 B를 연결하는 엣지의 더해지는 횟수만 변경되고 나머지 엣지는 유지된다.&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;정답은 서브트리와 관련이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A에서 B로 이동할 때 A-B엣지가 더해지는 수는 (B 쪽 엣지를 끊고 난 후 A의 자식 수) - (A쪽 엣지를 끊고 난 후 B의 자식 수) 만큼 더해지게 된다.&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;이는 기준점을 잡으면 해결할 수 있다. 즉 A를 루트로 생각한 후 dfs를 수행하며 자식의 노드 수만 저장을 한다면 (A 쪽 엣지를 끊고 난 후 B의 자식 수)는 A를 기준으로 dfs를 탐색했으므로 구해진 B의 자식 수이고, (B 쪽 엣지를 끊고 난 후 A의 자식 수)는 n - B의 자식수를 해주면 쉽게 구할 수 있다.&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;이를 통해 점화식을 dp[next] = dp[cur] + childCnt[next] * edgeWeight - edgeWeight * (n - childCnt[next])로 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 구할 때도 A를 기준으로 dfs를 수행해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740292825770&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class P_7812 {

    static int n;
    static ArrayList&amp;lt;ArrayList&amp;lt;Edge&amp;gt;&amp;gt; edges;
    static long[] dp;
    static int[] childCnt = new int[10001];
    static boolean[] visited = new boolean[10001];
    static class Edge{
        int idx, weight;
        Edge(int idx, int weight){
            this.idx = idx;
            this.weight = weight;
        }
    }

    public static int dfsCnt(int idx) {
        // 자신을 포함함
        visited[idx] = true;
        int ret = 1; // 자신의 수

        for (int i = 0;i &amp;lt; edges.get(idx).size();i++) {
            int next = edges.get(idx).get(i).idx;
            if (visited[next]) continue;
            int cnt = dfsCnt(next);
            ret +=  cnt;
            dp[idx] += ((long) edges.get(idx).get(i).weight * cnt) + dp[next];
        }
        childCnt[idx] = ret;
        return ret;
    }

    public static void dfs(int idx) { // 0을 기준으로 한 weight를 모두 구함
        visited[idx] = true;

        for (int i = 0;i &amp;lt; edges.get(idx).size();i++) {
            int next = edges.get(idx).get(i).idx;
            int weight = edges.get(idx).get(i).weight;
            if (visited[next]) continue;
            dp[next] = dp[idx] - (long) weight * childCnt[next] + (long) weight * (n - childCnt[next]);
            dfs(next);
        }
        return ;
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st;
        while(true) {
            n = Integer.parseInt(br.readLine());
            if (n == 0) break;
            dp = new long[n];
            int a, b, c;
            edges = new ArrayList&amp;lt;&amp;gt;();
            for (int i = 0; i &amp;lt; n; i++) {
                edges.add(new ArrayList&amp;lt;&amp;gt;());
                Arrays.fill(dp, 0);
            }
            for (int i = 0; i &amp;lt; n - 1; i++) { // 간선 양방향으로 입력 받기
                st = new StringTokenizer(br.readLine());
                a = Integer.parseInt(st.nextToken());
                b = Integer.parseInt(st.nextToken());
                c = Integer.parseInt(st.nextToken());
                edges.get(a).add(new Edge(b, c));
                edges.get(b).add(new Edge(a, c));
            }

            Arrays.fill(visited, false);
            dfsCnt(0);

            Arrays.fill(visited, false);
            dfs(0);
            long ans = Long.MAX_VALUE;
            for (int i = 0;i &amp;lt; n;i++) {
                ans = Math.min(ans, dp[i]);
            }
            bw.write(Long.toString(ans) + '\n');

        }
        bw.flush();
        bw.close();
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/286</guid>
      <comments>https://salmon16.tistory.com/286#entry286comment</comments>
      <pubDate>Sun, 23 Feb 2025 15:40:29 +0900</pubDate>
    </item>
    <item>
      <title>[백준] 평범한 배낭 12865번 (java) 냅색 1차원으로 풀이</title>
      <link>https://salmon16.tistory.com/285</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://www.acmicpc.net/problem/12865&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/12865&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀이 방법,&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 문제는 0-1 배낭 문제(0-1 Knapsack Problem)로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;1차원 DP&lt;/b&gt;&lt;/span&gt;를 활용하여 최적의 해결법을 찾는다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;DP 배열을 사용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;주어진 무게 제한 내에서 최대 가치를 찾는 방식&lt;/b&gt;&lt;span&gt;으로 풀이하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;DP 배열 정의&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;dp[j]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;무게 j일 때 배낭에 담을 수 있는 최대 가치&lt;/b&gt;&lt;span&gt;를 저장&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;초기값은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;으로 설정&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;각 물건을 순회하며 DP 테이블 갱신&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;현재 물건을 넣을 수 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;최대 무게부터 역순으로 탐색&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(이전 값이 유지되도록)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;현재 가방을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;선택하는 경우 vs. 선택하지 않는 경우&lt;/b&gt;&lt;span&gt;를 비교하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;dp&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;갱신&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;dp[j] = max(dp[j], dp[j - weight] + value)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1740201462871&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class P_12865 {

    static int n, k;
    static int[] dp = new int[100001];
    static public class BackPack{
        int weight, value;
        BackPack(int weight, int value) {
            this.weight = weight;
            this.value = value;
        }
    }
    static ArrayList&amp;lt;BackPack&amp;gt; backPacks = new ArrayList&amp;lt;&amp;gt;();


    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        st = new StringTokenizer(br.readLine());
        n = Integer.parseInt(st.nextToken()); // 배낭의 수
        k = Integer.parseInt(st.nextToken()); // 제한 무개
        for (int i = 0; i &amp;lt; n; i++) {
            st = new StringTokenizer(br.readLine());
            backPacks.add(new BackPack(Integer.parseInt(st. nextToken()), Integer.parseInt(st.nextToken())));
        }
        for (int i = 0;i &amp;lt; backPacks.size();i++){
            for (int j = k;j &amp;gt;= backPacks.get(i).weight;j--) {
                dp[j] = Math.max(dp[j], dp[j - backPacks.get(i).weight] + backPacks.get(i).value);
            }
        }
        System.out.println(dp[k]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>salmon16</author>
      <guid isPermaLink="true">https://salmon16.tistory.com/285</guid>
      <comments>https://salmon16.tistory.com/285#entry285comment</comments>
      <pubDate>Sat, 22 Feb 2025 14:18:07 +0900</pubDate>
    </item>
  </channel>
</rss>