题目:http://acm.hdu.edu.cn/showproblem.php?pid=5304

16个点的无向图,问能生成多少个n条边的连通图。(即多一条边的树)

先n^3 * 2^n 枚举全部的环。状压dp即可。dp[i][j]表示以i为终点,走了j状态集合的方案数。要枚举起点,每次走比起点大的点。所以要n^3 2^n枚举。

把环压缩成点。构造基尔霍夫矩阵。每种状态下n^3求生成树。

故总复杂度是 n^3 * 2^n + n^3 * 2^n

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = (1<<16)+10;
ll ans;
int f[N],dp[20][N];
bool d[20][20];
int n,m; ll exgcd(ll a,ll b,ll &x,ll &y)//乘法逆元返回的d是a,b的公约数。x是a mod b的逆元
{
if(b==0)
{
x=1ll;y=0;
return a;
}
ll d=exgcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-a/b*y;
return d;
} ll Gauss(int C[][20],int n)//计算n阶行列式的绝对值 % mod
{
ll ans=1ll;
int flag=1;//行列交换的次数
int i,j,k;
for(i=0;i<n;i++)
{
if(C[i][i]==0)
{
for(j=i+1;j<n;j++)
if(C[j][i])break;
if(j==n)return 0;//某列的值全是0的ans=0。
flag=!flag;
for(int k=i;k<n;k++)
swap(C[i][k],C[j][k]);//i和j行交换
}
ans=ans*C[i][i]%mod;//对角线相乘
ll x,y;
int tp=exgcd(C[i][i],mod,x,y);//x为逆元 for(k=i+1;k<n;k++)
C[i][k]=C[i][k]*x%mod; for(int j=i+1;j<n;j++)
for(int k=i+1;k<n;k++)
{
C[j][k]=(C[j][k]-(ll)C[j][i]*C[i][k])%mod;
if(j==k)
C[j][k]=(C[j][k]+mod)%mod;
}
for(k=i+1;k<n;k++)
C[i][k]=(ll)C[i][k]*C[i][i]%mod; } ans=(ans%mod+mod)%mod;
if(flag) return ans;
else return mod-ans;
} ll solve(int s){
int Kir[20][20];
int vis[20],col[20];
memset(Kir,0,sizeof(Kir));
memset(vis,0,sizeof(vis));
memset(col,-1,sizeof(col));
for(int i=0;i<n;i++)
if((1<<i)&s) vis[i]=1;
int num=0;
for(int i=0;i<n;i++)if(!vis[i])
col[i]=num++;
for(int i=0;i<n;i++)if(vis[i])
col[i]=num;
num++; for(int i=0;i<n;i++)
for(int j=0;j<n;j++)if(i!=j && col[i]!=col[j])
Kir[col[i]][col[j]] -= d[i][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)if(col[i]!=col[j])
Kir[col[i]][col[i]] += d[i][j]; return Gauss(Kir,num-1);
} int main(){
// freopen("e.in","r",stdin);
// freopen("my05.out","w",stdout);
while(scanf("%d%d",&n,&m)!=EOF){
ans = 0;
memset(d,0,sizeof(d));
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
u--,v--;
d[u][v] = d[v][u] = 1;
} memset(f,0,sizeof(f));
for(int st=0;st<n;st++){
memset(dp,0,sizeof(dp));
dp[st][(1<<st)] = 1;
for(int s=1;s<(1<<n);s++)if((1<<st)&s){
for(int i=0;i<n;i++)if(i>=st)
if(dp[i][s]){
for(int j=st+1;j<n;j++)
if( (s&(1<<j))==0 && d[i][j] )
dp[j][s|(1<<j)] = ( dp[i][s] + dp[j][s|(1<<j)])%mod;
if(d[i][st])
f[s] = ( dp[i][s] + f[s] )%mod;
}
}
} ll inv2 = (mod+1)/2;
for(int i=1;i<(1<<n);i++){
if(f[i]){
int co = 0;
for(int j=0;j<n;j++)if((1<<j)&i) co++;
if(co<=2) continue;
f[i] = ((ll)f[i]*inv2)%mod;
ans = (ans + (ll)f[i]*solve(i)%mod )%mod;
}
} printf("%I64d\n",ans); } return 0;
}

hdu5304 Eastest Magical Day Seep Group&#39;s Summer 状压dp+生成树的更多相关文章

  1. HDU 5304(Eastest Magical Day Seep Group&#39;s Summer-环加外向树生成树计数)[Template:Kirchhoff矩阵]

    Eastest Magical Day Seep Group's Summer Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 655 ...

  2. uva 11825 Hackers&#39; Crackdown (状压dp,子集枚举)

    题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有同样的n种服务),对每台计算机,你能够选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让很多其它的服务瘫痪( ...

  3. 状压dp Mondriaan&#39;s Dream poj2411

    超经典的一道题目,实现这题的方法也有非常多种 1.利用DFS建立矩阵,然后通过高速矩阵幂得到答案(运用于min(m,n)比較小.可是max(m,n)很大的情况) 2.利用dp状压解决 第一种在我的还有 ...

  4. group:状压dp,轮廓线

    神仙题.但是难得的傻孩子cbx没有喊题解,所以也就难得的自己想出来了一个如此神仙的题. 如果是自己想的,说它神仙是不是有点不合适啊..? 反正的确不好像.关键就在于这个标签.颓完标签就差不多会了. % ...

  5. group 状压dp

    应某些人要求,我把标签删掉了 这是一道好题. 一看$c<=16$果断状压,但是怎么压? 一个很显然的思路是,枚举上下两层的状态,每一层的状态极限有$C(c,c/2)$,c=16的时候有13000 ...

  6. [杂题]:group(状压DP+轮廓线)

    题目描述 $pure$在玩一个战略类游戏.现在有一个士兵方阵,每行有若干士兵,每个士兵属于某个兵种.行的顺序不可改变,且每一行中士兵的顺序也不可改变.但由于每一行都有$C$个位置($C$不小于任一行的 ...

  7. [生产环境数据恢复]innobackupex: fatal error: OR no &#39;datadir&#39; option in group &#39;mysqld&#39; in MySQL options

    1 运行恢复命令  [xxx@xxx-c001db1 tmp]$ time /usr/bin/innobackupex --rsync --user="user" --passwo ...

  8. hdu 4638 Group(离线+树状数组)

    Group Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Subm ...

  9. UVA 1484 - Alice and Bob&#39;s Trip(树形DP)

    题目链接:1484 - Alice and Bob's Trip 题意:BOB和ALICE这对狗男女在一颗树上走,BOB先走,BOB要尽量使得总路径权和大,ALICE要小,可是有个条件,就是路径权值总 ...

随机推荐

  1. 通讯框架 t-io 学习——websocket 部分源码解析

    前言 前端时间看了看t-io的websocket部分源码,于是抽时间看了看websocket的握手和他的通讯机制.本篇只是简单记录一下websocket握手部分. WebSocket握手 好多人都用过 ...

  2. airodump-ng使用手册

    选项: -i, --ivs 捕捉WEP加密的包,忽略出IV之外的所有的包,保存为.ivs格式 airodump-ng wls35u1 -i -w captures airodump-ng wls35u ...

  3. Varnish 实战项目

    实现基于Keepalived+Haproxy+Varnish+LNMP企业级架构 原理:缓存,又称加速器,用于加速运行速度较快的设备与较慢设备之间的通信.基于程序的运行具有局部性特征其能实现加速的功能 ...

  4. c++ const全局对象是如何处理的

    我主要是记录一个发现,目前我不能解释,先作个记录. const 只是一个 语义约束,由编译器强制实施的.使被约束的对象不能被直接访问修改. 我用 『直接』这词,因为在代码段中 ,用一个const 指针 ...

  5. R语言高性能编程(二)

    接着上一篇 一.减少内存使用的简单方法1.重用对象而不多占用内存 y <- x 是指新变量y指向包含X的那个内存块,只有当y被修改时才会复制到新的内存块,一般来说只要向量没有被其他对象引用,就可 ...

  6. mongoose返回值无法修改

    mongoose 查询方法 find 例:db.collections.find(query,function(err,doc) { 如果var res = doc[0]  是{name:'feife ...

  7. 掌握numpy(三)

    统计功能 前面都是介绍numpy的一些特性,被称为数学运算神器怎么能少了统计功能呢 ndarray的方法 a = np.array([[-2.5, 3.1, 7], [10, 11, 12]]) &g ...

  8. javaBean实体包区分

    随着软件工程结构越来越复杂,单一的entity实体包无法满足业务需要,可以采取PO,BO,DTO结构来分类实体. PO (Persistent Object):与数据库表数据关联的实体. BO(Bus ...

  9. sql 触发器,看完后对CHK有更深的理解

    触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程.触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. 什么是触发器? 触发器对表进行插入.更新.删除 ...

  10. nginx反向代理node.js获取客户端IP

    使用Nginx做node.js程序的反向代理,会有这么一个问题:在程序中获取的客户端IP永远是127.0.0.1 如果想要拿到真实的客户端IP改怎么办呢? 一.首先配置Nginx的反向代理 proxy ...