形象的表示就是
在这个N=3的矩阵中,每一条线就代表着 D1,p1×D2,p2×D3,p3×...×Dn,pN D 1 , p 1 × D 2 , p 2 × D 3 , p 3 × . . . × D n , p N
其中可以发现,相连的斜线为/就会让逆序对数+1,\就不增加
具体怎么算呢?
比如说上图中的淡蓝色吧,ta的排列是3 1 2,逆序对应该是2
看斜线的话
一开始是/,t++,t=1,ans+=t,ans=1
然后\,t不变,t=1,ans+=t,ans=2
要是向上面一样模拟的话。。。状态就有n!个,还需要一个个算的话想想就害怕
如果要快速计算行列式,我们需要知道行列式的性质
一个矩阵行列互换(A’[i][j]=A[j][i])得到矩阵A’,det(A)=det(A’)
这个似乎显然咯
互换行列式两行或两列的位置,det(A’)=-det(A)
那么我们有一个很好的推论:若矩阵第i行与第j行的值完全相同,det=0,因为交换这两行(列)得到的矩阵和以前一样,而det为相反数,则det=0
矩阵A中某一行的元素全部乘以常数k,则det(A’)=k*det(A)
根据行列式的定义式,可以发现,每一行肯定会在每一个状态里出现一个属于这一行的数字,因为这一行每一个数字都扩大了k倍,可以给每一个状态带来k倍的贡献,得证
若存在1<=i,j<=n,k为实数满足A[i][l]=k*A[j][l]对于所有1<=l<=n均成立,则det(A)=0
根据2、3性质可以得到,可以把常数k提出来,然后两行相等的话det=0,所以0*k=0
将第i行所有元素加上任意其他行元素的实数倍,det(A)不变
证明: 考虑排列p1,p2,p3…..pn对于答案的贡献
原始矩阵:s1=sign*A[1][p1]* A[2][p2]*….*A[n][pn]
新矩阵: s2=sign*A[1][p1]* A[2][p2]… A[n][pn]+sign*k * A[1][p1]* A[2][p2].. A[j][pi]*..A[n][pn]
而△=sigma(s2-s1)=0,因为△=后面加的一串,看看性质四可以发现后面的=0,所以得证
怎么快速求行列式的值呢?这里给出结论
对于第i行,我们希望将满足i+1<=j<=n的A[j][i]的值变为0,也就是用高斯消元的方法消成一个上三角,然后把a[i][i]这一部分的值乘起来就好了。
为什么呢?因为求这个变化后的矩阵和原来的矩阵行列式一样,也就是转化为求这个矩阵的行列式,可以发现除了排列 pi=i p i = i 之外,别的排列给出的贡献都是0,所以把a[i][i]乘起来就好了
注意每次交换两行的时候要记录次数,如果是奇数,答案还要乘上-1
这样就可以O(n^3)实现矩阵行列式的求解。
求一个图的生成树个数,首先构造度数矩阵D和邻接矩阵A
基尔霍夫矩阵K=D−A
我们去掉K矩阵的第N行和第N列,然后用高斯消元(取模情况下要使用辗转相除的高斯消元)得到新矩阵的上三角形
对角线乘积的绝对值(a[i][i])就是生成树个数
这里献上裸题:SPOJ HIGH
#include
#include
#include
#include
#define LL long long
using namespace std;
const double eps=1e-9;
const int N=20;
int n;double a[N][N],ans;
void gauss()
{
int opt=0;
for (int i=1;i<=n;i++)
{
if (a[i][i]int num=i;
for (int j=i+1;j<=n;j++)
if (fabs(a[j][i])>fabs(a[num][i])) num=j;
if (num==i) {ans=0;return;}
for (int j=i;j<=n;j++) swap(a[num][j],a[i][j]);
opt^=1;
}
for (int j=i+1;j<=n;j++)
{
double t=a[j][i]/a[i][i];
for (int k=i;k<=n;k++) a[j][k]-=a[i][k]*t;
}
}
for (int i=1;i<=n;i++) ans*=a[i][i];
if (opt==1) ans*=-1;
}
int main()
{
int T,m;scanf("%d",&T);
while (T--)
{
ans=1;memset(a,0,sizeof(a));
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;scanf("%d%d",&x,&y);
a[x][x]++; a[y][y]++; a[x][y]--; a[y][x]--;
}
n--;gauss();
printf("%.0lf\n",ans);
}
}
参考blog:dalaoA,dalaoB