LOJ:https://loj.ac/problem/2290c++
洛谷:https://www.luogu.org/problemnew/show/P4547git
首先考虑只有第一类边的状况,那么每种完美匹配必定会由\(n\)个边组组成,几率就是\(1/2^n\),对答案贡献为\(1\),那么问题就转化成了统计完美匹配个数。spa
设\(f[s1][s2]\)表示当前左边状况为\(s1\),右边为\(s2\),在把其余的点填满能够获得的完美匹配的种类数,而后就是普及组\(dp\),复杂度\(O(2^{2n})\),可是这样会重复计数,并且复杂度不对。code
若是咱们把\(s1\)严格每次都从高位到低位转移,而后上记忆化搜索,复杂度能够降到\(O(2^n\cdot n^2)\),且不会重复计数。get
考虑其余两类边,咱们硬点这些边都是单独的,几率\(50\%\),可是这样会算不对,第二类边组在两条边都选的时候贡献的几率为\(25\%\),可是应该是\(50\%\),因此咱们多加一个\(25\%\)的边组就行了,同理第三类边组添加一个几率为\(-25\%\)的边组,而后改一改上面的\(dp\),记搜转移就行了,\(f\)开不下能够用\(\rm map\)。it
#include<bits/stdc++.h> using namespace std; void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} #define lf double #define ll long long #define pii pair<int,int > #define vec vector<int > #define pb push_back #define mp make_pair #define fr first #define sc second #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++) const int maxn = 1e4+10; const int inf = 1e9; const lf eps = 1e-8; const int mod = 1e9+7; const int inv2 = 5e8+4; const int inv4 = 2.5e8+2; int add(int x,int y) {return x+y>=mod?x+y-mod:x+y;} int del(int x,int y) {return x-y<0?x-y+mod:x-y;} int mul(int x,int y) {return 1ll*x*y-1ll*x*y/mod*mod;} map<int,int > f; int a[maxn],b[maxn],cnt,n,m; int dfs(int s) { if(s==(1<<(n<<1))-1) return 1; if(f.find(s)!=f.end()) return f[s];int now=0,ans=0; for(int i=n-1;~i;i--) if(!(s&(1<<i))) {now=1<<i;break;} for(int i=1;i<=cnt;i++) if(!(a[i]&s)&&(now&a[i])) ans=add(ans,mul(b[i],dfs(s|a[i]))); return f[s]=ans; } int main() { read(n),read(m); for(int i=1,s,s2,t,x,y;i<=m;i++) { read(t),read(x),read(y);x--,y--; s=1<<x|(1<<(y+n));a[++cnt]=s,b[cnt]=inv2; if(!t) continue;read(x),read(y);x--,y--; s2=1<<x|(1<<(y+n));a[++cnt]=s2,b[cnt]=inv2; if(s&s2) continue; a[++cnt]=s|s2,b[cnt]=t==1?inv4:mod-inv4; }write(mul(dfs(0),(int)pow(2,n))); return 0; }