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

题目

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

思路

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

代码

#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;
}
posted @   stoorz  阅读(122)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
· SQL Server统计信息更新会被阻塞或引起会话阻塞吗?
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目
点击右上角即可分享
微信分享提示