题意
求一个带权无向图有多少不同的最短路树。
分析
直接把最短路DAG建出来然后跑矩阵树定理就好了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
typedef long long LL;
const int N=55;
const int inf=1000000000;
const int MOD=1000000007;
int n,ma[N][N],dis[N],a[N][N];
bool vis[N];
char str[N];
std::queue<int> que;
void spfa()
{
for (int i=1;i<=n;i++) dis[i]=inf;
dis[1]=0;que.push(1);vis[1]=1;
while (!que.empty())
{
int u=que.front();que.pop();
for (int i=1;i<=n;i++)
if (dis[u]+ma[u][i]<dis[i])
{
dis[i]=dis[u]+ma[u][i];
if (!vis[i]) que.push(i),vis[i]=1;
}
vis[u]=0;
}
}
void build()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (dis[i]+ma[i][j]==dis[j]) a[j][j]++,(a[i][j]+=MOD-1)%=MOD;
}
int det(int n)
{
int ans=1;
for (int i=1;i<=n;i++)
{
for (int j=i+1;j<=n;j++)
if (a[j][i])
{
while (a[j][i])
{
if (a[j][i]<a[i][i])
{
for (int k=i;k<=n;k++) std::swap(a[i][k],a[j][k]);
ans=-ans;
}
int w=a[j][i]/a[i][i];
for (int k=i;k<=n;k++) (a[j][k]+=MOD-(LL)a[i][k]*w%MOD)%=MOD;
}
}
}
for (int i=1;i<=n;i++) ans=(LL)ans*a[i][i]%MOD;
ans+=ans<0?MOD:0;
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",str+1);
for (int j=1;j<=n;j++)
ma[i][j]=str[j]!='0'?str[j]-'0':inf;
}
spfa();
build();
for (int i=1;i<n;i++)
for (int j=1;j<n;j++)
a[i][j]=a[i+1][j+1];
printf("%d",det(n-1));
return 0;
}