bzoj 5056: OI游戏 最短路+矩阵树定理

题意

求一个带权无向图有多少不同的最短路树。
n 50

分析

直接把最短路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;
}

猜你喜欢

转载自blog.csdn.net/qq_33229466/article/details/80429269
今日推荐