본문 바로가기

카테고리 없음

[H1626] 트리 흑백 색칠

반응형

  • 정점이 N개인 트리가 주어진다. 동철이는 각 정점을 검은색 아니면 하얀색 중 하나로 칠하려고 한다. , 어떤 간선으로 연결된 두 정점이 모두 검은색이면 안 된다. 색칠하는 것으로 가능한 경우의 수는 몇 가지인가?


    예를 들면 아래와 같은 트리가 있다고 하면



    가능한 모든 색칠의 경우의 수는


    (하얀색/하얀색), (하얀색/검은색), (검은색/하얀색), (검은색/검은색)


    [(1번정점의색/2번정점의색)]이지만, 위 조건을 만족하는 경우의 수는 (검은색/검은색)을 제외한 나머지 3개이다.


     


     [입력]


    첫 번째 줄에 테스트 케이스의 수 T가 주어진다.


    각 테스트 케이스의 첫 번째 줄에는 하나의 정수 N(2≤N≤100,000)이 주어진다.


    다음 N-1개의 줄의 각 줄에는 두 정수 x,y(1 ≤ x < y ≤ N)가 공백으로 구분되어 주어진다. 이는 정점의 번호를 1번에서 N번까지로 매길 때 x번 정점과 y번 정점을 연결하는 간선이 있다는 의미이다. 주어진 그래프는 트리임이 보장된다.


     


     [출력]


    각 테스트 케이스마다 ‘#t’를 찍고 하나의 빈 칸으로 구분하여, 트리의 각 정점을 색칠할 수 있는 경우의 수를 출력한다. 이 수는 매우 클 수 있으므로 1,000,000,007로 나눈 나머지를 출력하도록 한다. (t는 테스트 케이스 번호이며, 1부터 시작한다.)


     


    입력 예제

    출력 예제

    2 // 테스트 케이스 개수

    2 // 첫 번째 테스트 케이스 N

    1 2 // x, y

    5 // 두 번째 케이스 N

    1 3 // x1, y1,

    2 3 // x2, y2

    3 4 // x3, y3

    4 5 // x4, y4

    #1 3

    #2 14


     

#include <stdio.h>
#include <malloc.h>
 
#define MAX 100000
#define MOD 1000000007
 
enum { W, B };
 
typedef long long LL;
 
typedef struct _EDGE {
    int idx;
    struct _EDGE* next;
} EDGE;
 
typedef struct {
    int chk;
    EDGE* edge;
} VRTX;
 
int N, Ei;
VRTX V[MAX + 1];
EDGE E[MAX * 2 + 1];
LL D[MAX + 1][2];
 
void add_edge(int from, int to)
{
    E[Ei].idx = to;
    E[Ei].next = V[from].edge;
    V[from].edge = &E[Ei++];
}
 
LL calc(int idx, int WB)
{
    if (D[idx][WB] == -1) {
        LL ret = 1;
        EDGE* cur = V[idx].edge;
 
        V[idx].chk = 1;
        while (cur) {
            if (!V[cur->idx].chk)
                if (WB == W)
                    ret = ret * ((calc(cur->idx, W) + calc(cur->idx, B)) % MOD) % MOD;
                else
                    ret = ret * calc(cur->idx, W) % MOD;
            cur = cur->next;
        }
        V[idx].chk = 0;
        D[idx][WB] = ret;
    }
 
    return D[idx][WB];
}
 
int main(void)
{
    int TC, from, to;
    scanf("%d", &TC);
    for (int tc = 1; tc <= TC; tc++) {
        scanf("%d", &N);
 
        Ei = 0;
        for (int i = 1; i <= N; i++) {
            V[i].chk = V[i].edge = 0;
            D[i][W] = D[i][B] = -1;
        }
         
        for (int i = 1; i < N; i++) {
            scanf("%d %d", &from, &to);
            add_edge(from, to);
            add_edge(to, from);
        }
                 
        printf("#%d %lld\n", tc, (calc(1, W) + calc(1, B)) % MOD); 
    }
    return 0;


반응형