Circuit 2023“钉耙编程”中国大学生算法设计超级联赛4-3 hdu7322

39 篇文章 0 订阅
该文描述了一个编程问题,涉及有向图和边权。问题要求找到图中环的最小权值及对应最小环的数量。使用Floyd算法计算任意两点间的最短路径,通过枚举边来检测环并更新最小环信息。代码实现包括初始化矩阵、Floyd算法的优化以及主函数中的输入处理和结果输出。
摘要由CSDN通过智能技术生成

Problem - 7322

题目大意:有一个n个点的边权有向图,求图中环的权的最小值以及相应最小环的数量

1<=n<=500

思路:要求一个如下图的环的大小,我们只需知道u到v的最短路径加上v到u的边权

这样的话我们需要求出任意两点之间的最短路,再枚举边即可,所以用到floyd算法,我们在每次路径更新时,或者找到权值相同的路径时,都要维护最短路径的数量cnt,然后在每次第k个点更新完成后,可以直接枚举小于k的点i与k之间的边,如果有环,就判断以k为顶点的环:ma[i][k]+dis[k][i]是不是最小值,如果是最小值相等,也要更新数量

#include<__msvc_all_public_headers.hpp>
//#include<bits/stdc++.h>
using namespace std;
const int N = 505;
typedef long long ll;
const ll INF = 1e14;
ll ma[N][N];
ll dis[N][N];
ll cnt[N][N];
ll ans1 = INF;
const ll MOD = 998244353;
int n, m;
ll ans2 = 0;
void init()
{//初始化
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			ma[i][j] = 0;
			dis[i][j] = INF;
			cnt[i][j] = 0;
		}
		dis[i][i] = 0;
		cnt[i][i] = 0;//没有自环
	}
	ans1 = INF;
	ans2 = 0;
}
void floyd()
{
	for (int k = 1; k <= n; k++)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (dis[i][j] > dis[i][k] + dis[k][j])
				{//更新最短路
					dis[i][j] = dis[i][k] + dis[k][j];
					cnt[i][j] = cnt[i][k] * cnt[k][j] % MOD;//更新最短路条数
				}
				else if (dis[i][j] == dis[i][k] + dis[k][j])
				{//与最短路相等也要维护数量
					cnt[i][j] = (cnt[i][j] + cnt[i][k] * cnt[k][j] % MOD) % MOD;
				}
			}
		}
		for (int i = 1; i <= k - 1; i++)
		{//枚举已经更新好的顶点
			if (ma[k][i])
			{
				if (ma[k][i] + dis[i][k] < ans1)
				{//当前环更小
					ans1 = ma[k][i] + dis[i][k];
					ans2 = cnt[i][k];
				}
				else if (ma[k][i] + dis[i][k] == ans1)
				{//与最小环等长
					ans2 = (ans2 + cnt[i][k]) % MOD;
				}
			}
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		init();
		for (int i = 1; i <= m; i++)
		{
			int u, v;
			ll w;
			cin >> u >> v >> w;
			ma[u][v] = w;
			cnt[u][v] = 1;
			dis[u][v] = w;
		}
		floyd();
		if (ans1 == INF)
		{
			cout << -1 << " " << -1 << endl;
		}
		else
		{
			cout << ans1 << " " << ans2 << endl;//题目描述的不清楚,路径长度是不能取模的
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timidcatt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值