"매칭 트리 트리 DP"

<> 예

<첫 번째 업데이트>


<텍스트>

나무 일치

기술

오늘 작업을 관리 게으른 게으른. 부드러운 발견의 망상에서 창 밖을 응시, 우리는 창을 통해 n 개의 노드의 트리를 볼 수 있었던. N-1 에지를 포함하는 n 개의 노드가 트리, 및 n 노드 유니콤이다. 즉, 포함, 두 지점 사이의 최단 경로 트리 에지의 두 숫자 사이의 거리.
변덕 관리 그림의 나머지 부분을 삭제 후 최대 일치하는 고유 수 있도록 삭제 가장자리 나무의 세트를 (비어있을 수 있습니다) 선택합니다. 관리는 가장자리 세트의 조건을 충족 할 수를 알고 싶습니다. 많이 될 수있는 조건을 만족 모서리의 수를 설정, 998,244,353 모듈로하시기 바랍니다.
정합 그래프에서는 조건이 동일한 노드 중 양측에 의존하지 않는, 그래프의 에지들의 부분 집합이다. 일치하는 모든 수치는 에지들의 최대 개수는 매칭 그래프의 최대 매칭이다.

입력 형식

제 라인 정수 n.
다음에, 각각 두 개의 정수, BI 인공 지능 N-1 행은 노드 인공 지능 에지 바이 사이 나타낸다.
3000 ≤ N-2 ≤ 40 %
2 ≤ N ≤-300000 100 %

출력 형식

설정된 조건을 만족하는 에지의 정수가 모듈 (244) 998 (353)을 요청하고 출력

샘플 입력

4 
1 2 
1 3 
1 4

샘플 출력

4

결심

유일한 지점이 고립 또는 가장 큰 경기의 일부 중 하나의 그림에 해당 사실에 최대 일치 : 첫 번째 문제의 의미를 변환합니다.

이 조건의 필요성 즉, 유일한 최대 매칭, 조건이 충족되어야합니다 말을하는 것입니다, 분명하다. 마찬가지로, 우리는 또한 조건이 적합 함을 증명할 수있는 다음 reductio 광고 absurdum가, 포인트가있는 가정은 고립도 최대 일치, 그리고 가장 큰 단일 경기이 그림도 아니다. 우리는 두 개의 사례를 토론

\ (1 \) 에도 지점이 시점에서 가장 큰 경기에 속하는, 매치의 고유성의 가장 큰 모순
\ (2 \) 도 가장 큰 경기, 최대 및 최대 일치에 속하지 않는이 점의 포인트 모순

그래서이 두 가지 명제는 동일합니다.

那么我们就可以考虑树形\(dp\)计数。设\(f1[x]\)代表节点\(x\)等待他的父节点与他匹配,子树\(x\)的方案数,\(f2[x]\)代表节点\(x\)孤立,子树\(x\)的方案数,\(f3[x]\)代表节点\(x\)已经与某一个儿子匹配,子树的\(x\)的方案数。然后列状态转移方程:

\[f1_{x}=\prod_{y\in son(x)}(f2_y+2f3_y)\\f2_x=\prod_{y\in son(x)}(f2_y+f3_y)\\f3_x=\sum_{y\in son(x)} \left ( \frac{\prod_{z\in son(x),z\not= y}(f2_z+2f3_z)}{f2_y+2f3_y}*f1_y \right )\]

为什么\(f3\)都要乘\(2\),是因为当前节点\(x\)\(f3\)这种完成状态之间的边可连可不连。关于第三个状态转移方程,其含义为选一个点\(y\)\(f1\)状态与其匹配,剩下的同理随便选。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 300020;
const long long Mod = 998244353;
struct edge { int ver,next; } e[N*2];
int n,t,Head[N];
long long f1[N],f2[N],f3[N];
// f1 means which node is waiting mathcing
// f2 means which node is isolated
// f3 means which node has already matched
inline void insert(int x,int y)
{
    e[++t] = (edge){y,Head[x]} , Head[x] = t;
    e[++t] = (edge){x,Head[y]} , Head[y] = t;
}
inline void input(void)
{
    scanf("%d",&n);
    for ( int i = 1; i < n; i++ )
    {
        int x,y;
        scanf("%d%d",&x,&y);
        insert( x , y );
    }
}
inline long long power(long long a,long long b)
{
    long long res = 1;
    while ( b )
    {
        if ( 1 & b ) res = res * a % Mod;
        a = a * a % Mod , b >>= 1;
    }
    return res;
}
inline void mul(long long &a,long long b) { a = a * b % Mod; }
inline void add(long long &a,long long b) { a += b; if ( a >= Mod ) a -= Mod; }
inline void dp(int x,int f)
{
    f1[x] = f2[x] = 1LL;
    long long val = 1LL;
    for ( int i = Head[x]; i; i = e[i].next )
    {
        int y = e[i].ver;
        if ( y == f ) continue;
        dp( y , x );
        mul( f1[x] , ( f2[y] + 2 * f3[y] ) % Mod );
        mul( f2[x] , ( f2[y] + f3[y] ) % Mod );
        mul( val , ( f2[y] + 2 * f3[y] ) % Mod );
    }
    for ( int i = Head[x]; i; i = e[i].next )
    {
        int y = e[i].ver;
        if ( y == f ) continue;
        long long inv = power( f2[y] + 2 * f3[y] , Mod-2 );
        long long sum = val;
        mul( sum , inv ) , mul( sum , f1[y] );
        add( f3[x] , sum );
    }
}
int main(void)
{
    input();
    dp( 1 , 0 );
    printf("%lld\n", ( f2[1] + f3[1] ) % Mod );
    return 0;
}

<后记>

추천

출처www.cnblogs.com/Parsnip/p/11203680.html