@codeforces - 1221G@ Graph And Numbers


@description@

Given a point n m undirected graph edges.

Each point is now required to write 0 or 1, a weight value is defined for the side edges of the two weights connected and.

Right how many programs, such that the presence of at least one side is 0, at least one side with a weight of 1, 2 with a weight of at least one side.

Input
The first line contains two numbers n and m (1≤n≤40, 0≤m≤n * (n -1) / 2), represents the number of points and edges.
Next m lines of two integers xi and yi (1≤xi, yi≤n, xi ≠ yi), describe two end points of an edge.
To ensure that no heavy side.

Output
Output the number of legal program.

Examples
input
6 5
1 2
2 3
3 4
4 5
5 1
output
20

input
4 4
1 2
2 3
3 4
4 1
output
4

@solution@

n <= 40 implies that meet in the middle. Requirements imply the inclusion-exclusion counting scheme.

First, consider how the inclusion-exclusion, we count the number of the following scenarios:
f1: no restrictions.
f2: Force 0 does not appear.
f3: 1 does not appear forced.
f4: Forced 2 does not appear.
f5: 0 and 1 are not forced to appear.
f6: 0 and 2 are not forced to appear.
f7: Forced 1 and 2 do not appear.
f8: Force 0, 1 and 2 does not appear.
The final answer ans = f1 - f2 - f3 - f4 + f5 + f6 + f7 - f8.

Next, consider how specific count.
First readily available f1 = 2 ^ n.
If all connected components are of a size, a total of m number of connected components, the f8 = 2 ^ m; otherwise f8 = 0.
If all connected components are bipartite graph, there are m connected components, then f6 = 2 ^ m; otherwise f6 = 0.
If the size is the number of connected components is 1 k, then f5 = f7 = 2 ^ k.
If the total number of connected components as m, f3 = 2 ^ m.

While the remaining f2, f4 need bi-directional search. Since f2 = f4, we might consider only f4.
If the point u has a value of 0, it adjacent dots without limitation; otherwise, if the point value of u is 1, it is 0 only adjacent points.

We enumerate the first half of the binary states, which must point to get to zero, and then determine the current state is legitimate.
Note F [s] s represents legality, legality of 1, otherwise 0; g [s] represents a binary s '<= s a f [s'] sum, and to high dimensional prefix.

Query half of the binary state enumeration, first determine whether legitimate, then get the first half of which is 0, which is 0 or 1. Direct access to the value g.

@accepted code@

#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
int n, m; ll G[40 + 5];
int fa[40 + 5], siz[40 + 5];
int find(int x) {
    return fa[x] = (fa[x] == x ? x : find(fa[x]));
}
void unite(int x, int y) {
    int fx = find(x), fy = find(y);
    if( fx != fy ) fa[fx] = fy, siz[fy] += siz[fx];
}
ll check(int x) {
    ll d[40 + 5] = {};
    for(int i=0;i<n;i++)
        d[i] = -1;
    queue<int>que; que.push(x); d[x] = 0;
    while( !que.empty() ) {
        int f = que.front(); que.pop();
        for(int i=0;i<n;i++)
            if( (G[f]>>i) & 1 ) {
                if( d[i] == -1 ) {
                    d[i] = d[f] ^ 1;
                    que.push(i);
                }
                else {
                    if( d[i] != (d[f] ^ 1) )
                        return 0;
                }
            }
    }
    return 2;
}
ll solve1() {
    ll ret1 = 1, ret2 = 1, ret3 = 1, ret4 = 1;
    for(int i=0;i<n;i++)
        if( fa[i] == i ) {
            ret1 <<= 1;
            ret2 = ret2*check(i);
            ret3 = (siz[i] == 1) ? (ret3<<1) : ret3;
            ret4 = (siz[i] == 1) ? (ret4<<1) : 0;
        }
    return ret2 - ret1 + (ret3<<1) - ret4;
}
ll f[1<<20];
void dfs1(int d, int mxd, int s1, int s2) {
    if( d == mxd ) {
        f[s1]++;
        return ;
    }
    dfs1(d + 1, mxd, s1, s2);
    if( !(s2 & (1LL<<d)) )
        dfs1(d + 1, mxd, s1|(1LL<<d), s2|G[d]);
}
int mid, t;
ll dfs2(int d, int mxd, ll s) {
    if( d == mxd ) {
        s = s & t, s = s ^ t;
        return f[s];
    }
    ll ret = dfs2(d + 1, mxd, s);
    if( !(s & (1LL<<d)) )
        ret += dfs2(d + 1, mxd, s|G[d]);
    return ret;
}
ll solve2() {
    mid = (n>>1), t = (1<<mid) - 1;
    dfs1(0, mid, 0, 0);
    for(int i=0;i<mid;i++)
        for(int j=0;j<=t;j++)
            if( j & (1LL<<i) ) f[j] += f[j^(1LL<<i)];
    return dfs2(mid, n, 0);
}
int main() {
    scanf("%d%d", &n, &m);
    for(int i=0;i<n;i++) fa[i] = i, siz[i] = 1;
    for(int i=1;i<=m;i++) {
        int x, y; scanf("%d%d", &x, &y), x--, y--;
        G[x] |= (1LL<<y), G[y] |= (1LL<<x), unite(x, y);
    }
    printf("%lld\n", (1LL<<n) + solve1() - (solve2()<<1));
}

@details@

A communication start without taking into account the size of the block (i.e. the side not communicating block) a case where, WA once.

Since then did not open long long, WA several times.

Guess you like

Origin www.cnblogs.com/Tiw-Air-OAO/p/11568191.html