[HDU 4997 Biconnected] 无向图的边双联通子图计数 状压DP

来源:互联网 发布:优酷视频下载器 mac 编辑:程序博客网 时间:2024/04/29 10:20

题目

http://acm.hdu.edu.cn/showproblem.php?pid=4997

分析

无向图的边双联通子图计数 状压DP

膜拜了SJTU的代码

用联通的子图个数减去非双联通子图的个数

1.联通子图的个数的做法

用connected[s]表示点集s的子图的联通子图的个数

用cntEdge[s]表示s中的边数,cntEdge[s1][s2]表示s1和s2之间的边数,那么

connected[s] = 2^cntEdge[s] - connected[s'] * 2^cntEdge[s-s']

s'为包含同一个点的联通子图,包含同一个点是为了避免重复,即将一个联通子集剥离出来的方案数

2.非双联通子图的做法

想法是用一个包含同一个点的双联通子图用树边去连接若干个联通子图

用expand[s1][s2]表示以集合s2通过树边连接s1的方案数,其中s2是s1的子集,那么

expand[s1][s2] = sigma{connected[s'] * cntEdge[s'][s2] * expand[s1 - s'][s2]},其中s'为s1的子集

3.双联通子图的做法

设biconnected[s]表示点集s的子图的边双联通子图个数,那么

biconnected[s] = connect[s] - biconnected[s'] * expand[s][s']

s'为包含同一个点的双联通子图

代码

/************************************************** *        Problem:  HDU 4997 *         Author:  clavichord93 *          State:  Accepted **************************************************/#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;const int MAX_N = 10;const int MAX_S = 1 << MAX_N;const int Mod = (int)1e9 + 7;int n, m;bool edge[MAX_N][MAX_N];int cntEdge[MAX_S][MAX_S];long long connected[MAX_S];long long biconnected[MAX_S];long long expand[MAX_S][MAX_S];int main() {    #ifdef LOCAL_JUDGE    freopen("in.txt", "r", stdin);    #endif    int T;    scanf("%d", &T);    for (int cas = 1; cas <= T; cas++) {        scanf("%d %d", &n, &m);        memset(edge, true, sizeof(edge));        for (int i = 1; i <= m; i++) {            int a, b;            scanf("%d %d", &a, &b);            a--;            b--;            edge[a][b] = false;            edge[b][a] = false;        }        for (int i = 0; i < n; i++) {            edge[i][i] = false;        }        int cntState = 1 << n;        for (int i = 0; i < cntState; i++) {            for (int j = 0; j < cntState; j++) {                if (i == j || (i & j) == 0) {                    int &ref = cntEdge[i][j];                    ref = 0;                    for (int x = 0; x < n; x++) {                        if ((i >> x) & 1) {                            int low = (i == j) ? x + 1 : 0;                            for (int y = low; y < n; y++) {                                if ((j >> y) & 1) {                                    ref += edge[x][y];                                }                            }                        }                    }                }            }        }        connected[0] = 1;        biconnected[0] = 1;        for (int mask = 1; mask < cntState; mask++) {            int lowbit = mask & -mask;            {                long long &ref = connected[mask];                ref = 1ll << cntEdge[mask][mask];                for (int subset = mask ^ lowbit; subset; subset = (subset - 1) & (mask ^ lowbit)) {                    ref -= connected[mask ^ subset] * (1ll << cntEdge[subset][subset]);                }            }            {                for (int target = mask ^ lowbit; target; target = (target - 1) & (mask ^ lowbit)) {                    int source = mask ^ target;                    int _lowbit = target & -target;                    long long &ref = expand[mask][source];                    ref = 0;                    for (int subset = target ^ _lowbit; ; subset = (subset - 1) & (target ^ _lowbit)) {                        int set = target ^ subset;                        ref += connected[set] * cntEdge[set][source] * expand[mask ^ set][source];                        if (subset == 0) {                            break;                        }                    }                }                expand[mask][mask] = 1;            }            {                long long &ref = biconnected[mask];                ref = connected[mask];                for (int subset = mask ^ lowbit; subset; subset = (subset - 1) & (mask ^ lowbit)) {                    ref -= biconnected[mask ^ subset] * expand[mask][mask ^ subset];                }            }        }        int ans = biconnected[cntState - 1] % Mod;        printf("%d\n", ans);    }    return 0;}


0 0
原创粉丝点击