弗洛伊德求最小简单环

为了看下自己学会没  

例题:

杭州有N个景区,景区之间有一些双向的路来连接,现在8600想找一条旅游路线,这个路线从A点出发并且最后回到A点,假设经过的路线为V1,V2,....VK,V1,那么必须满足K>2,就是说至除了出发点以外至少要经过2个其他不同的景区,而且不能重复经过同一个景区。现在8600需要你帮他找一条这样的路线,并且花费越少越好。

输入:第一行是2个整数N和M(N <= 100, M <= 1000),代表景区的个数和道路的条数。
接下来的M行里,每行包括3个整数a,b,c.代表a和b之间有一条通路,并且需要花费c元(c <= 100)。

输出:对于每个测试实例,如果能找到这样一条路线的话,输出花费的最小值。如果找不到的话,输出"It's impossible.".

sample:

输入

3 3
1 2 1
2 3 1
1 3 1
3 3
1 2 1
1 2 3
2 3 1

输出

3

It's impossible.

题目中要求“k>2”为我们排除了只有两个顶点无法成环的情况,即可以将问题简化为形成环路、顶点数大于等于三、不重复经过同一顶点的 弗洛伊德算法求无向图最小权值环路问题。

实现这个算法我们需要定义两个二维数组,其中一个通过三重循环更新存储顶点间的最短路径,另一个存储原始权值数据。

核心思想

假设有vn个顶点。三重循环最外层是中间顶点的序号(由0-n,为了遍历所有顶点作为中间顶点时的情况)

中层和内层分别是起点(0-中间顶点)和终点(起点序号+1-中间顶点,为了保证中间顶点不被包含在已经更新过的最小路径集中,且不会由自己出发走向自己还有a[i][j]、a[j][i]这种重复比较的情况)的序号,

第一个内部二重循环比较已有的ans值(所求最小环权值和)和原始表中起点终点距离与更新后的最短路径距离之和(循环条件能够保证这个最短路径集中不含外层循环当前所取中间节点序号值

)(刚好构成一个环路)的大小,第二个二重循环更新将当前中间节点纳入最短路径集后的最短路径

#include<stdio.h>
#include<stdlib.h> 
#include<math.h>
const int MAXN = 10;
const int N = 10000;
typedef struct graph
{
	int nov,noe;
	int m[MAXN][MAXN];
 } G;
 
 int priv[MAXN][MAXN];// 中间节点 
 int cost[MAXN][MAXN]; //花费 

void Floyd(graph G,int p[MAXN][MAXN],int c[MAXN][MAXN])
{
	int v,w,k;
	int ans = N;
	for(v=0;v<G.nov;v++)	//初始化 
		for(w=0;w<G.nov;w++)
		{	
			p[v][w] = w;
			c[v][w] = G.m[v][w];  
		}
		
	for(k=0;k<G.nov;k++)
	{
		for(v=0;v<k;v++)
			for(w=v+1;w<kw++)
			{
				ans = ans<(c[v][w]+G.m[v][k]+G.m[k][w])?ans:(c[v][w]+G.m[v][k]+G.m[k][w]);
			}

		for(v=0;v<G.nov;v++)
			for(w=0;w<G.nov;w++)
			{
				if(c[v][w]>c[v][k]+c[k][w])
				{
					c[v][w]=c[v][k]+c[k][w];
					p[v][w]=p[v][k];
				}
			}
	}									//弗洛伊德算法 
	if(ans == N)printf("It's impossible"); 
	else printf("%d",ans);
 } 
 
 int main()
 {
	int v,w,i;
	graph G;
	scanf("%d%d",&G.nov,&G.noe);		
	for(v=0;v<G.nov;v++)	//初始化 
		for(w=0;w<G.nov;w++)
		{	
			if(v==w) 	G.m[v][w] = 0;
			else			G.m[v][w] = N;  
		}
		
		
	for(i=0;i<G.noe;i++)			
		{   
			scanf("%d %d",&v,&w);	 
			scanf("%d",&G.m[v-1][w-1]);
			G.m[w-1][v-1]=G.m[v-1][w-1] ; 
		}
	
	Floyd(G,priv,cost);
	return 0;	
 }
 
 
 
 
 
 
 
 
 
 
 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值