【hdu5304】生成树计数—基尔霍夫矩阵 DP
2015-09-12 10:32
357 查看
给一个无向图,求有多少个子图是基环树。
枚举环后缩点,再求生成树计数。
2^n枚举环上的点,dp预处理出每个集合的环的个数(默认以编号最小的点为起点),用f[i][s]表示环尾为i,点集为s。
枚举环后缩点,再求生成树计数。
2^n枚举环上的点,dp预处理出每个集合的环的个数(默认以编号最小的点为起点),用f[i][s]表示环尾为i,点集为s。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define Rep(i, x, y) for (int i = x; i <= y; i ++) #define Dwn(i, x, y) for (int i = x; i >= y; i --) #define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex) using namespace std; typedef long long LL; const int N = 18, mod = 998244353, S = (1 << 17) + 2; int n, m, nx, d , c , l; LL a , ans, f [S]; LL Pow(LL x, LL y) { if (x < 0) x += mod; LL z = 1; while (y) { if (y & 1) z = z * x % mod; x = x * x % mod, y >>= 1; } return z; } LL Gauss() { int fl = 1; Rep(i, 1, l) { Rep(j, i, l) if (a[j][i]) { if (i != j) fl *= -1; Rep(k, 1, l) swap(a[i][k], a[j][k]); break ; } if (!a[i][i]) return 0; LL tp = Pow(a[i][i], mod - 2); Rep(j, i + 1, l) if (a[j][i]) { LL z = a[j][i] * tp % mod; Rep(k, 1, l) a[j][k] = (a[j][k] - (z * a[i][k] % mod) + mod) % mod; } } LL s = fl; Rep(i, 1, l) s = (s * a[i][i]) % mod; return (s + mod) % mod; } int main() { while (scanf ("%d%d", &n, &m) != EOF) { nx = 1 << n; ans = 0; memset(d, 0, sizeof(d)); Rep(i, 1, n) Rep(j, 0, nx) f[i][j] = 0; Rep(i, 1, m) { int x, y; scanf ("%d%d", &x, &y); d[x][y] = d[y][x] = 1; } Rep(i, 1, n) { f[i][1 << i-1] = 1; Rep(s, (1 << i-1), nx - 1) if ((((1 << i-1) - 1) & s) == 0){ Rep(j, i, n) if (f[j][s]) { Rep(k, i + 1, n) if ((s & (1 << k-1)) == 0 && d[j][k]) { (f[k][s + (1 << k-1)] += f[j][s]) %= mod; } } } } Rep(s, 1, nx - 1) { Rep(i, 1, n) Rep(j, 1, n) a[i][j] = 0; int k; LL sc = 0; Rep(i, 0, n - 1) if ((1 << i) & s) { k = i + 1; break ; } c[k] = l = 1; Rep(i, k + 1, n) if ((1 << i-1) & s) { (sc += f[i][s] * d[i][k]) %= mod; c[i] = 1; } Rep(i, 1, n) if (!((1 << i-1) & s)) c[i] = ++ l; if (n - l < 2) continue ; Rep(i, 1, n) { Rep(j, i + 1, n) if (d[i][j]) { int x = c[i], y = c[j]; a[x][y] --, a[y][x] --, a[x][x] ++, a[y][y] ++; } } l --; (ans += (Gauss() * sc % mod) * Pow(2, mod - 2)) %= mod; } printf ("%I64d\n", ans); } return 0; }
相关文章推荐
- CSS小贴士(垂直居中和百分比下调整盒模型填充)
- 数据挖掘(8):朴素贝叶斯分类算法原理与实践
- 位运算及其应用详解
- Remove Duplicates from Sorted Array
- 内核之旅 --- 内核模块学习1---内核模块参数传递
- 内核之旅 --- 内核模块学习1---内核模块参数传递
- 深入解析字符串的比较方法:“==”操作符;String.Equals方法;String.Compare方法;String.CompareOrdinal方法。
- [Leetcode]Closest Binary Search Tree Value
- 汽车租赁管理系统及所涉及面向对象的一般步骤
- 数据挖掘(7):分类算法评价
- 苹果的玫瑰金与小米的粉色版
- hdu acm 1171 Big Event in HDU
- 在一个指定的div中拖拽
- JAVA中的SimpleDateFormat yyyy和YYYY的区别
- 数据挖掘(6):决策树分类算法
- linux下weblogic 12c 之软件安装
- C/C++常用头文件及函数汇总
- python与shell的3种交互方式介绍
- c++ profilers
- 数据挖掘(5):使用mahout做海量数据关联规则挖掘