SpringBoot: 後臺介面文件 - 基於Swagger3
阿新 • • 發佈:2021-07-29
是一個很經典集合問題。
在一個點集中,一定可以分割成若干個聯通子集。
如果我們設 \(f_i\) 為一個點集的聯通方案,\(g_i\) 為一個點集的所有方案。
我們先任取一個點,考慮列舉一個集合和這個點不聯通。
那麼我們知道這樣不連通的方案 \(\sum g[j] \times\ f[i\ xor\ j]\)。
依據簡單的容斥:
\(f_i = g_i - \sum_{s\in(i\ xor\ j)}\ g[j] \times\ f[i\ xor\ j]\)。
答案為 \(f_{2^n - 1}\)。
在實現有細節,即先把當前集合丟掉 \(lowbit(i)\),在列舉不連通的子集。
#include<iostream> #include<cstdio> #define ll long long #define mod 1000000007 #define N 20 #define M (1 << 17) ll n; ll c[N][N]; ll f[M],g[M]; int main(){ scanf("%lld",&n); for(int i = 1;i <= n;++i) for(int j = 1;j <= n;++j) scanf("%lld",&c[i - 1][j - 1]); ll K = (1 << n) - 1; for(int i = 0;i <= K;++i){ g[i] = 1; for(int j = 0;j <= n - 1;++j){ for(int k = j + 1;k <= n - 1;++k){ if(((i >> j) & 1) && ((i >> k) & 1)) g[i] = (g[i] * (c[j][k] + 1)) % mod; } } } for(int i = 0;i <= K;++i){ f[i] = g[i]; int t = i ^ (i & -i); for(int j = t;j > 0;j = (j - 1) & t){ f[i] = (f[i] - g[j] * f[i ^ j] % mod + mod) % mod; } } std::cout<<f[K]<<std::endl; }