P6175 无向图的最小环问题(Floyd)

【题目链接】

link

【解题思路】

题目中说了,至少要有三点才能算一个环,那么我们其实只需要枚举这三个点再将连接他们几个的三条边加起来就可以了。
如果做完了Floyd再跑一次枚举三个点,我们会发现时间复杂度会慢一点,所以我们考虑进行一些优化,一边Floyd,一边求最小环,这样我们的时间复杂度会快一点。

证明:当我们以 k k k 为中转点的时候,我们 1 ∼ k − 1 1\sim k-1 1k1 的点一定是处理过的并且结果为最优,那么我们就以 k k k 为一个点,再在 1 ∼ k − 1 1\sim k-1 1k1 枚举两个点就可以啦。

解释一下三边:首先定义三个点, i , j , k i,j,k i,j,k i , j i,j i,j 为与 k k k 相邻的两个点。

  1. k k k i i i 连接的边。
  2. k k k i i i 连接的边。
  3. i i i j j j 连接的边。

证明:
k 和 i 之 间 的 做 短 路 或 k 和 j 之 间 的 做 短 路 可 能 会 有 一 些 重 叠 , 这 样 就 不 是 一 个 环 啦 , 所 以 k 必 须 与 i , j 相 邻 k和i之间的做短路或k和j之间的做短路可能会有一些重叠,这样就不是一个环啦,所以k必须与i,j相邻 kikjki,j
Tips:我们要注意初始化,如果太大三边之和会爆int,当有重边是选择最小的一条。

【CODE】

#include<bits/stdc++.h>
using namespace std;
int n,m,u,v,d,minn;
int mp[111][111];
int dis[111][111];
int main()
{
	cin>>n>>m;
	minn=10000000;
	memset(dis,0x3f/2,sizeof(dis));
	memset(mp,0x3f/2,sizeof(mp));
	for (int i=1;i<=m;i++)
	{
		cin>>u>>v>>d;
		dis[u][v]=mp[u][v]=min(mp[u][v],d);
		dis[v][u]=mp[v][u]=min(mp[v][u],d);
	}
	for (int k=1;k<=n;k++)
	{
		for (int i=1;i<=k-1;i++)
			for (int j=i+1;j<=k-1;j++)//提高效率,前面的点都枚举过啦
				if (dis[i][j]+mp[k][i]+mp[k][j]<minn)//三条边之和
					minn=dis[i][j]+mp[k][i]+mp[k][j];
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				if (dis[i][j]>dis[k][i]+dis[k][j])
					dis[i][j]=dis[k][i]+dis[k][j];
	}
	if (minn==10000000)
		cout<<"No solution.";
	else cout<<minn;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值