CF D

题意

给你一个图,每个节点可以赋值1,2,3三种数字,相邻的节点的和必须是奇数,问有多少中方法。

分析:

很容易就可以发现如果这个图中是有奇数的环的话,那这是肯定不行的 ,否则这个环的贡献是为2^sumji+2^sumou , 总贡献为每个的环的贡献相乘,一个点也为环;

#include<bits/stdc++.h>
using namespace std ;
#define mod 998244353
#define ll long long
const int maxn= 3e5+10;
vector<int>G[maxn];
int color[maxn];
int sumji,sumou,n,m,fa;
ll qsm(ll a,ll b)//快速幂
{
    ll ans=1;
    while(b)
    {
        if(b%2)
        ans=(ans*a)%mod;
        b/=2;
        a=(a*a)%mod;
    }
    return ans;
}
void init()
{
    for(int i=1 ; i<=n ; i++)
    G[i].clear();
    for(int i=1 ; i<=n ; i++)
    color[i]=0;

}
void dfs(int x , int c)
{
    if(c==1)
    sumji++;
    if(c==2)
    sumou++;
    color[x]=c;
    for(int i=0 ; i<G[x].size() ; i++)
    {
        if(color[G[x][i]]==0)///3-c,如果是1,那么就变成了2,如果是2,就变成了1。如果是3,那么就变成了0,那样的话,就相当于没有遍历,以后偶还是会遍历到的。。
        dfs(G[x][i],3-c);
        else if(color[G[x][i]]==c)///有奇数环
        {
            fa=0;
            break;
        }

    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=1 ; i<=m ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        fa=1;
        ll ans=1;
        for(int i=1  ; i<=n ; i++)
        {
            if(color[i]==0)
            {
                sumji=sumou=0;
                dfs(i,1);
                if(!fa) break;
                ans = (ans * (qsm(2,sumji)+qsm(2,sumou)) %mod)%mod;
            }
        }
        if(!fa)
        puts("0");
        else
        printf("%I64d
",ans);
    }
}
View Code
原文地址:https://www.cnblogs.com/shuaihui520/p/10164591.html