【每日一题】边的染色(dfs+思维 / 联通块+xor)

边的染色

https://ac.nowcoder.com/acm/problem/17067

Solution
题意:给定一个无向图,有一些边已经染色,求让你染色剩下的边使得每个环的异或和都为0的方案数。

好难想!好难想!好难想!重要的事情要说三遍!

1.思维点:题解很巧妙,把对边染色转移到对点染色,取边为两个端点的xor,这样的话每个环的异或和肯定为0,因为每个点都xor了两次~

2.答案的贡献:
考虑一个联通块里面没有边被染色,那么每个点都有染成 0/1 的选择,设cnt为联通块中的点数目,那么可以考虑成 2^cnt, 但是想一下,因为是算边的染色方案而不是点的染色方案,如果对所有点取反,边权不变,所以每个联通块对答案的贡献为: 2^(cnt-1) 。

再考虑已经有x条边被染色的联通块,那么如果这些染色的边已经有一个点确定一个值,那么染色的边剩下的点的值就都确定了,所以每个连通块对答案的贡献要除以: 2^x (x条边有x+1个点)

3.判断合法性:类似于判断二分图染色一样,遍历已经确定的边和随便染上1/0,根据边权由点权异或得到判断是否冲突。

参考题解,用三个dfs来解决问题:
dfs1: 慢慢染色,看是否合法。
dfs2: 统计所有联通块的点数
dfs3: 统计有染色边的联通块中的点数

Code

#include<bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ll long long
#define fi first
#define se second
#define inf 0x3f3f3f3f
#define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
void put1(){ puts("Yes") ;}void put2(){ puts("No") ;}void put3(){ puts("-1"); }
ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a =
(a*a)%p;b >>= 1;}return ans%p;}
const int mo=998244353; const int mod=1000000007;

const int manx=1e5+5;

vector<pair<ll,ll> >g[manx];
ll col[manx],vis[manx];
ll cnt=0;

ll dfs1(ll u,ll co){
    col[u]=co;
    for(auto x: g[u]){
        ll v=x.fi,w=x.se;
        if(w==-1) continue;
        if(col[v]!=-1 && co^col[v]!=w) return 0;
        if(col[v]==-1 && !dfs1(v,co^w)) return 0;
    }
    return 1;
}

void dfs2(ll u){
    cnt++; vis[u]=1;
    for(auto x:g[u]){
        ll v=x.fi,w=x.se;
        if(vis[v]) continue;
        dfs2(v);
    }
}

void dfs3(ll u){
    cnt++; vis[u]=1;
    for(auto x:g[u]){
        ll v=x.fi,w=x.se;
        if(vis[v]||w==-1) continue;
        dfs3(v);
    }
}
int main(){
    ll n=read(),m=read();
    for(int i=1;i<=m;i++){
        ll u=read(),v=read(),w=read();
        g[u].pb(mp(v,w));  g[v].pb(mp(u,w));
    }
    memset(col,-1,sizeof(col));
    for(int i=1;i<=n;i++){
        if(col[i]==-1){
            if(!dfs1(i,1)){
                cout<<0<<endl;
                return 0;
            }
        }
    }
    ll k=0;
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            cnt=0;
            dfs2(i);
            k+= cnt-1;
        }
    }
    for(int i=1;i<=n;i++) vis[i]=0;
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            cnt=0;
            dfs3(i);
            k-= cnt-1;
        }
    }
    ll ans=1;
    for(int i=1;i<=k;i++){
        ans=ans*2;
        ans%=mo;
    }
    printf("%lld\n",ans);
    return 0;
}
全部评论

相关推荐

牛客963010790号:为什么还要收藏
点赞 评论 收藏
分享
10-15 03:05
门头沟学院 Java
CADILLAC_:凯文:我的邮箱是死了吗?
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务