[ZHOJ3293]朝暮

[ZHOJ3293]朝暮

题目大意:

\(n(n\le10^5)\)个点,\(m(m\le n+5)\)条边的无向图进行黑白染色。要求相邻两个点不能都是黑色,问有多少染色方法。

思路:

将多出来的\(6\)条边进行容斥,强制这些边都是黑色。时间复杂度\(\mathcal O(6^2n)\)

源代码:

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef long long int64;
const int N=1e5+1;
const int mod=1e9+7;
int n,m,f[2][N],cnt;
std::vector<int> e[N];
struct Edge {
    int u,v;
};
Edge edge[6];
inline void add_edge(const int &u,const int &v) {
    e[u].push_back(v);
    e[v].push_back(u);
}
int b[N];
void dfs(const int &x,const int &par) {
    f[0][x]=b[x]!=1;
    f[1][x]=b[x]!=0;
    for(unsigned i=0;i<e[x].size();i++) {
        const int &y=e[x][i];
        if(y==par) continue;
        dfs(y,x);
        f[0][x]=(int64)f[0][x]*(f[0][y]+f[1][y])%mod;
        f[1][x]=(int64)f[1][x]*f[0][y]%mod;
    }
}
class DisjointSet {
    private:
        int anc[N];
        int find(const int &x) {
            return x==anc[x]?x:anc[x]=find(anc[x]);
        }
    public:
        void reset() {
            for(register int i=1;i<=n;i++) anc[i]=i;
        }
        void merge(const int &x,const int &y) {
            anc[find(x)]=find(y);
        }
        bool same(const int &x,const int &y) {
            return find(x)==find(y);
        }
};
DisjointSet s;
int main() {
    n=getint(),m=getint();
    std::fill(&b[1],&b[n]+1,-1);
    s.reset();
    for(register int i=0;i<m;i++) {
        const int u=getint(),v=getint();
        if(s.same(u,v)) {
            edge[cnt++]=(Edge){u,v};
        } else {
            add_edge(u,v);
            s.merge(u,v);
        }
    }
    int ans=0;
    for(register int i=0;i<1<<cnt;i++) {
        for(register int j=0;j<cnt;j++) {
            if((i>>j)&1) b[edge[j].u]=b[edge[j].v]=1;
        }
        dfs(1,0);
        ans+=((f[0][1]+f[1][1])%mod)*((__builtin_popcount(i)&1)?-1:1);
        ans=(ans%mod+mod)%mod;
        for(register int j=0;j<cnt;j++) {
            if((i>>j)&1) b[edge[j].u]=b[edge[j].v]=-1;
        }
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2018-08-10 20:32 skylee03 阅读(...) 评论(...) 编辑 收藏