• 【洛谷P6178】【模板】Matrix-Tree 定理


    题目

    题目链接:https://www.luogu.com.cn/problem/solution/P6178
    给定一张 (n) 个结点 (m) 条边的带权图(可能为无向图,可能为有向图)。
    定义其一个生成树 (T) 的权值为 (T) 中所有边权的乘积。
    求其所有不同生成树的权值之和,对 (10^9+7) 取模。

    思路

    一般的矩阵树定理只能处理生成树数量的情况,但是这道题要求我们输出所有生成树权值之和。
    我们可以把一条边 ((x,y,z)) 拆成 (z)((x,y,1)) 的边,这样原来的一棵生成树,假设其权值为 (k),就变成了 (k) 棵生成树。此时只要求生成树数量即可。
    对于有向边的情况,如果要求外向树,那么一条边 ((x,y)) 能贡献的就只有 (g[y][y])(g[x][y])。证明不会。
    注意需要把自环去掉。
    时间复杂度 (O(n^3))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=310,MOD=1e9+7;
    int n,m,type;
    ll g[N][N];
    
    ll fpow(ll x,ll k)
    {
    	ll ans=1;
    	for (;k;k>>=1,x=x*x%MOD)
    		if (k&1) ans=ans*x%MOD;
    	return ans;
    }
    
    ll dit()
    {
    	ll f=1,res=1;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=n;j++)
    			g[i][j]=(g[i][j]%MOD+MOD)%MOD;
    	for (int i=2;i<=n;i++)
    	{
    		for (int j=i;j<=n;j++)
    			if (g[j][i])
    			{
    				if (j!=i) f=-f;
    				for (int k=2;k<=n;k++)
    					swap(g[j][k],g[i][k]);
    				break;
    			}
    		ll inv=fpow(g[i][i],MOD-2);
    		for (int j=i+1;j<=n;j++)
    			if (g[j][i])
    			{
    				ll base=inv*g[j][i]%MOD;
    				for (int k=1;k<=n;k++)
    					g[j][k]=((g[j][k]-base*g[i][k])%MOD+MOD)%MOD;
    			}
    	}
    	for (int i=2;i<=n;i++) res=res*g[i][i]%MOD;
    	return (res*f%MOD+MOD)%MOD;
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&type);
    	for (int i=1,x,y,z;i<=m;i++)
    	{
    		scanf("%d%d%d",&x,&y,&z);
    		if (x==y) continue;
    		if (type)
    			g[x][y]-=z,g[y][y]+=z;
    		else
    			g[x][y]-=z,g[y][x]-=z,g[x][x]+=z,g[y][y]+=z;
    	}
    	printf("%lld",dit());
    	return 0;
    }
    
  • 相关阅读:
    Nexus3.0私服搭建
    JavaScript
    Spring基础
    Hibernate注解
    HTML5
    Apache Tomcat
    Java安装(Ubuntu)
    C++ 日期 & 时间
    C++ 引用
    C++ 指针
  • 原文地址:https://www.cnblogs.com/stoorz/p/14233784.html
Copyright © 2020-2023  润新知