白準-15900号(樹木脱出)


質問元:https://www.acmicpc.net/problem/15900
質問する

  • 普段から仲の悪いメンバーと亨錫は、いよいよ真剣勝負.勝元と亨錫は2人とも親しい仁燮が対決を決めた.「木脱出」という将棋ゲームです.

  • 「ツリー脱出」は、N個の頂点を持つツリー型ゲームボードと、いくつかのゲーム言語で構成されています.ツリーの各頂点には、番号1~Nが付いています.1番の頂点は「ルートノード」と呼ばれ、そのルートノードを中心に頂点間で親子関係が確立されます.サブノードがないことをリーフノードと呼びます.

  • このゲームは2人が交代でゲームボードの上でゲーム馬を移動するゲームです.最初は、木の中の各葉ノードにゲーム馬が置かれていました.誰かの番になると、現在存在するゲーム馬から1匹を選び、ノードの親ノードに移動します.この過程で、1つのノードに複数のゲーム馬が配置される可能性があります.このように移動すると、ゲーム馬がルートノードに到達すると、直ちにゲーム馬がクリアされる.すべてのプロセスが完了すると、次の人の番になります.このように続けていくと、ゲーム馬は存在せず、選べない人になります.

  • メンバーを軽んじる亨錫はあっさりとこのゲームのラインをメンバーに渡しただから成元はまず亨錫を始めてから始めますこれまでハンソクと対決するたびに負けてきたメンバーは、怒りに満ちていた.今度の対決で必ず勝って、ヘンソクの鼻を折ろうとした.だからゲームを始める前に、ゲームボードの形を見て、このゲームに勝つかどうかを事前に知りたいだけです.メンバーにこのゲームに勝てるかどうか教えてくれる番組を作ってメンバーを助けましょう
  • 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 Main {
    
        private static List<Integer>[] adjList;
        private static boolean[] visited;
        private static int result;
    
        public static void main(String[] args) throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    
            int N = Integer.parseInt(reader.readLine()); // 정점 개수. 간선의 수는 N - 1개(이게 홀수, 리프가 홀수가 돼야된다)
            adjList = new List[N + 1]; // 1-based index
            visited = new boolean[N + 1];
            for (int i = 1; i <= N; i++) {
                adjList[i] = new ArrayList<>();
            }
    
            for (int i = 0; i < N - 1; i++) {
                StringTokenizer tokenizer = new StringTokenizer(reader.readLine());
                int x = Integer.parseInt(tokenizer.nextToken());
                int y = Integer.parseInt(tokenizer.nextToken());
    
                adjList[x].add(y);
                adjList[y].add(x);
            }
    
            dfs(1, 0);
    
            System.out.println(result % 2 == 0 ? "No" : "Yes");
        }
    
        private static void dfs(int num, int sum) {
            visited[num] = true; // 방문 처리
    
            for (int i = 0; i < adjList[num].size(); i++) {
                if (!visited[adjList[num].get(i)]) {
                    visited[adjList[num].get(i)] = true;
                    dfs(adjList[num].get(i), sum + 1);
                }
            }
    
            // dfs를 마친 후 리프 노드일 때만 값을 누적해준다. 리프 노드 -> 인접 리스트의 크기가 1(부모 정보만 가지고 있기 때문에)
            if (adjList[num].size() == 1) result += sum;
        }
    
    }
    
    これは最初から完全に間違った扱いをしている問題です.設計は
  • 論理を間違えて、時間で検索して、最終的に解読できません.
  • 事実論理は簡単です.成元は1回1回移動するので、1回で完成すると成元が勝つ.つまり、ツリーから全リーフノードまでの合計が奇数であれば、ゲーム全体が奇数となり、メンバーが勝つ.
  • 隣接表、何度か使ったと思いますが、久しぶりに使ったので思い出せません.隣接リストを作成してdfsを実行しながら、リーフノードに到達すると、値を積算することで値全体を得ることができます.