生成树计数
HDU 5304:
题目:给一个n个点,m条边的图,求去掉m-n条边使图连通的方案数.
思路:先状压dp出以某个点集能组成的环的数量,然后缩点用matrixTree定理做.
/* * @author: Cwind */ #include <bits/stdc++.h> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-4) #define INF (1000000300) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; const ll MOD= 998244353; const int MAXN = 17; void exgcd(int a, int b, int &x, int &y) { if (b) { exgcd(b, a % b, y, x); y -= a / b * x ; } else { x = 1; y = 0; } } int inv(int a){ int x, y, b = MOD; exgcd(a, b, x, y); if (x < 0) x += MOD; return x; } int n,m; struct Matrix { ll a[20][20]; Matrix() { memset(a, 0, sizeof(a)); } void clear() { memset(a, 0, sizeof(a)); } ll det(int n)//求行列式的值模上MOD,需要使用逆元 { ll res = 1; for(int i = 0;i < n;i++) { for(int j = i;j < n;j++) if(a[j][i]!=0) { for(int k = i;k < n;k++) swap(a[i][k],a[j][k]); if(i != j) res = (-res+MOD)%MOD; break; } if(a[i][i] == 0) { res = 0;//不存在(也就是行列式值为0) break; } for(int j = i+1;j < n;j++) { //int mut = (a[j][i]*INV[a[i][i]])%MOD;//打表逆元 ll mut = (a[j][i]*inv((int)a[i][i]))%MOD; for(int k = i;k < n;k++) { a[j][k] = (a[j][k]-(a[i][k]*mut))%MOD; if(a[j][k] < 0 ) a[j][k] += MOD; } } res = (res * a[i][i])%MOD; } return res; } }; const int maxn=17; bool G[17][17]; ll dp[1<<17][17]; ll sum[1<<17]; bool inq[1<<17]; int Q[1<<17]; int front,back; void caldp(){ memset(inq,0,sizeof inq); front=back=0; for(int i=0;i<n;i++){ dp[(1<<i)][i]=1; Q[back++]=(1<<i); inq[(1<<i)]=1; } while(front<back){ int mask=Q[front++]; int s=__builtin_ffs(mask);s--; for(int t=s;t<n;t++){ if(!(mask&(1<<t))||dp[mask][t]==0) continue; if(G[s][t]) sum[mask]=(sum[mask]+dp[mask][t])%MOD; for(int j=s+1;j<n;j++){ if(mask&(1<<j)) continue; if(!G[t][j]) continue; dp[mask|(1<<j)][j]=(dp[mask|(1<<j)][j]+dp[mask][t])%MOD; if(!inq[mask|(1<<j)]&&dp[mask|(1<<j)][j]) Q[back++]=mask|(1<<j),inq[mask|(1<<j)]=1; } } } } int in[17]; Matrix C; ll solve(){ ll ans=0; for(int i=1;i<(1<<n);i++){ if(__builtin_popcount(i)<3||!sum[i]) continue; C.clear(); int cnt=0; for(int j=0;j<n;j++){ if(i&(1<<j)) in[j]=0; else in[j]=++cnt; } for(int j=0;j<n;j++){ for(int k=j+1;k<n;k++){ if(G[j][k]&&in[j]!=in[k]){ C.a[in[j]][in[j]]++,C.a[in[k]][in[k]]++; C.a[in[j]][in[k]]--,C.a[in[k]][in[j]]--; } } } ans=(ans+sum[i]*inv(2)%MOD*C.det(cnt))%MOD; } return ans; } int main(){ freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("/home/slyfc/CppFiles/out","w",stdout); while(scanf("%d%d",&n,&m)!=EOF){ memset(dp, 0, sizeof(dp)); memset(G, 0, sizeof(G)); memset(sum, 0, sizeof(sum)); for(int i=0;i<m;i++){ int x,y; scanf("%d%d",&x,&y); G[x-1][y-1]=G[y-1][x-1]=1; } caldp(); ll ans=solve(); printf("%lld\n",ans); } return 0; }

浙公网安备 33010602011771号