BZOJ5297 CQOI2018 社交网络
考前挣扎
有向图生成树
我们知道对于无向图生成树可以通过矩阵树定理来算具体就是
度数矩阵 - 邻接矩阵 去掉任意一行一列得到余子式 对行列式求值
有向图生成树分为外向和内向两种
外向生成树当然是所有边指向儿子 他的矩阵树定理是这个样子
对于有向边(x,y)度数矩阵d[y][y] ++ 邻接矩阵e[x][y] ++
内向生成树所有边指向父亲
对于有向边(x,y)度数矩阵d[x][x] ++ 邻接矩阵e[x][y] ++
(说白了就是外向生成树反过来)
记忆的一个方法就是度数矩阵只记录入边(就是生成树的入边 【哪里不会点哪里
然后照常进行度数-邻接 然后我们由于是有向边 那么我们去掉的一行一列(i,i)就表示以i为根
然后正常行列式求值即可
(这个题小坑点 边是反着读的= =
//Love and Freedom.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define ll long long
#define mdn 10007
#define N 300
using namespace std;
int a[N][N],n,m;
int inv[mdn];
int gauss()
{
int ans = 1;
for(int i=1,j;i<=n;i++)
{
if(!a[i][i])
{
for(j=i+1;j<=n;j++)
if(a[j][i]) break;
if(j>n) return 0;
swap(a[j],a[i]);
ans = -ans;
}
int iv = inv[a[i][i]];
for(int j=i+1;j<=n;j++)
{
int w = iv*a[j][i]% mdn;
for(int k=i;k<=n;k++)
a[j][k] = (a[j][k]-w*a[i][k]%mdn +mdn)%mdn;
}
}
for(int i=1;i<=n;i++)
ans = ans*a[i][i]%mdn;
return ans<0?ans+mdn:ans;
}
int main()
{
int x,y; inv[1] = 1;
for(int i=2;i<mdn;i++)
inv[i] = (mdn-mdn/i)*inv[mdn%i]%mdn;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
x--; y--;
a[x][x]++; a[y][x]--;
}
n--; printf("%d\n",gauss());
return 0;
}