Codeforces 1332 F Independent Set ——树形DP

题意:

给你一棵树,问你它的所有边子集的所有点独立集的情况数是多少。
边子集就是边的子集且任何一个存在的点都有至少一条边连着。点独立集就是任意两个点在图中没有边连着。

题解:

这个边子集搞的我不知所措,一直没看懂。。那么就是当前点如果取了,它的所有儿子都不能取,它如果不取的话,所有儿子可取可不取。但是还有一种情况:它不和这个儿子相连,那么用dp[i][2]表示。
那么状态转移方程就是:

		sum=(dp[ne][0]+dp[ne][1]-dp[ne][2]+mod)%mod;
        dp[x][0]=dp[x][0]*(dp[ne][0]+dp[ne][1]+sum)%mod;
        dp[x][1]=dp[x][1]*(dp[ne][0]+sum)%mod;
        dp[x][2]=dp[x][2]*sum%mod;

就是乘法原理。为什么要减去dp[ne][2],因为无论这个点取0还是1,如果它不与儿子相连,都无所谓,也就是多算了一次。
最后减去空集的情况

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
#define ll long long
const ll mod=998244353;
ll dp[N][3];
struct node{
    int to,next;
}e[N*2];
int cnt,head[N];
void add(int x,int y){
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
ll ans;
void dfs(int x,int fa){
    dp[x][0]=dp[x][1]=dp[x][2]=1;
    ll sum=0;
    for(int i=head[x];~i;i=e[i].next){
        int ne=e[i].to;
        if(ne==fa)continue;
        dfs(ne,x);
        sum=(dp[ne][0]+dp[ne][1]-dp[ne][2]+mod)%mod;
        dp[x][0]=dp[x][0]*(dp[ne][0]+dp[ne][1]+sum)%mod;
        dp[x][1]=dp[x][1]*(dp[ne][0]+sum)%mod;
        dp[x][2]=dp[x][2]*sum%mod;
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    int n,x,y;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs(1,0);
    printf("%lld\n",(dp[1][0]+dp[1][1]-dp[1][2]-1+mod)%mod);
    return 0;
}
发布了584 篇原创文章 · 获赞 33 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/105375992
今日推荐