题意:有
N
个城市,
让每个公司修一条路,使得
N
个城市构成一棵树 。求方案数。
学习了一下高斯消元的辗转相除做法。
那么这个题容斥一下,
N−1
个人的方案数-
N−2
个人的方案数+
N−3
个人的方案数……
分别用矩阵树定理算出答案。
复杂度
O(2n∗n3)
【代码】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#define N 200005
#define Mod 1000000007
#define INF 200001
using namespace std;
typedef long long ll;
ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n;ll ans;
ll a[20][20];
int num[20],X[20][400],Y[20][400];
void Add(int x)
{
for(int i=1;i<=num[x];i++)
{
static int xx,yy;
xx=X[x][i],yy=Y[x][i];
a[xx][xx]++,a[yy][yy]++;
a[xx][yy]--,a[yy][xx]--;
}
}
ll Gauss_Elimination()
{
ll rtn=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
while(a[j][i])
{
ll t=a[i][i]/a[j][i];
for(int k=i;k<=n;k++)
a[i][k]=(a[i][k]-t*a[j][k])%Mod;
for(int k=i;k<=n;k++) swap(a[i][k],a[j][k]);
rtn=-rtn;
}
}
rtn=rtn*a[i][i]%Mod;
if(rtn==0) return 0;
}
return (rtn+Mod)%Mod;
}
int main()
{
n=read();n--;
for(int i=1;i<=n;i++)
{
num[i]=read();
for(int j=1;j<=num[i];j++) X[i][j]=read(),Y[i][j]=read();
}
int Mx=1<<n;
for(int i=1;i<Mx;i++)
{
memset(a,0,sizeof(a));int sum=0;
for(int j=0;j<n;j++) if(i&(1<<j))
Add(j+1),sum++;
ll t=Gauss_Elimination();
ans=(ans+t*(((sum&1)==(n&1))?1:-1))%Mod;
}
ans=(ans+Mod)%Mod;
printf("%lld\n",ans);
return 0;
}