最小环问题 ( Floyed )

hdu1599

在这里插入图片描述

解题报告:
要通过此题就要明白 f l o y e d floyed floyed 算法原理及其每步的含义。

		for(int k=1;k<=n;k++){
			for(int i=1;i<=n;i++){
				for(int j=1;j<=n;j++){
					mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
				}
			}
		}
		其本质就是动态规划 
		k作为阶段必须置于最外层,i,j作为附加状态置于内层
		mp<k,i,j>可以理解为 经过若干个编号不超过k的节点从i到j的最短路,进而转化为两个子问题:
		1.经过给若干个编号不超过k-1的节点从i到j最短路
		2.节点i经过k节点到j节点
		因此: mp<k,i,j> = min(mp<k-1,i,j>, mp<k-1,i,k> + mp<k-1,k,j>)
		再通滚动数组优化得到 mp<i,j>
		在枚举每次的ki时,我们就已经求出来 1~k-1之间的最短路。

回到本题求最小环:
假设存在一条最小环 u − v − k − u u-v-k-u uvku,既然是最小环,当拆掉 u − v u-v uv时, v − k − u v-k-u vku就是 ( u , v ) (u,v) (u,v)最短路。
再回到前面floyed算法每次枚举 k i k_i ki 的时候我们就已经求出来1~k-1之间的最短路,前 k − 1 k-1 k1 个的点不包含 k k k 节点且它们之间的最短路径之间也不经过 k k k 节点。
从前 k − 1 k-1 k1 个点中取两点 i , j i,j ij ( i , j ) (i,j) (i,j) 之间的最短路已经求得且不经过节点 k k k,再跟据floyed原理以k为中间节点进行更新得到最小环 i − j − k − i i-j-k-i ijki

#include<bits/stdc++.h>
#define LL  long long
#define pii pair<LL,int>
#define all(x) x.begin(),x.end()
#define wp(x) write(x),putchar('\n')
#define wpl(x) write(x),putchar(' ')
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 2e5 + 5;
inline int read() {
	int s = 0, f = 1;
	char  ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {s = (s << 1) + (s << 3) + ch - '0'; ch = getchar();}
	return s * f;
}
inline void write(LL x) {
	if (x < 0) putchar('-'), x = -x;
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
int mp[105][105],g[105][105];
int main(){
	int n,m,u,v,w;
	while(scanf("%d%d",&n,&m)!=EOF){
		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) g[i][j]=mp[i][j]=(i==j)?0:1e8;
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&u,&v,&w);
			g[u][v]=mp[u][v]=min(mp[u][v],w);
			g[v][u]=mp[v][u]=min(mp[v][u],w);
		}
		int ans=1e8;
		for(int k=1;k<=n;k++){
			for(int i=1;i<k;i++){
				for(int j=i+1;j<k;j++){
					ans=min(ans,mp[i][j]+g[i][k]+g[k][j]);
				}
			}
			for(int i=1;i<=n;i++){
				for(int j=1;j<=n;j++){
					mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
				}
			}
		}
		if(ans==1e8) printf("No solution.\n");
		else printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值