Floyd-Warshall算法(求解任意两点间的最短路) 详解 + 变形 之 poj 2253 Frogger

/*
好久没有做有关图论的题了,复习一下。
---------------------------------------------------------
 
任意两点间的最短路(Floyd-Warshall算法)
动态规划:
dp[k][i][j] := 节点i可以通过编号1,2...k的节点到达j节点的最短路径。
 
使用1,2...k的节点,可以分为以下两种情况来讨论:
	(1)i到j的最短路正好经过节点k一次
		dp[k-1][i][k] + dp[k-1][k][j]
	(2)i到j的最短路完全不经过节点k
		dp[k-1][i][j]
故:dp[k][i][j] = min(dp[k-1][i][k] + dp[k-1][k][j], dp[k-1][i][j])
 
空间可优化:dp[i][j] = min(dp[i][k] + dp[k][j], dp[i][j])
 
初始值:
	dp[0][i][j] = 0 (i == j)
	dp[0][i][j] := 边i->j的权值
	如果i和j之间不存在边,dp[i][j] = INF (0x3f3f3f3f)
 
 
时间复杂度:O(|V|^3)
可以处理边是负数的情况,判断图中是否有负圈,只需检查是否存在dp[i][i]是负数的顶点i就可以了。
 
---------------------------------------------------------------------------------
poj 2253 Frogger
对于此题,求的是:
	To execute a given sequence of jumps, a frog's jump range obviously must be at least 
	as long as the longest jump occuring in the sequence.
	The frog distance (humans also call it minimax distance) between two stones therefore is defined as
	the minimum necessary jump range over all possible paths between the two stones. 
	即:一条路径中需要跳跃很多次,但存在一次跳跃在所有跳跃中需要跳的距离最长,这个距离即可称为这条路径中需要跳跃的最长距离,
	    找出A石头到达B石头所有路径的需要跳跃的最长距离,其中最短的最长距离即为答案,即:The frog distance。
 
Floyd-Warshall算法会遍历到i->j所有的路径,所以我们可以改变dp状态,解决此问题:
	dp[k][i][j] := 节点i可以通过编号1,2...k的节点到达j节点的路径中,需要跳跃的最短的最长距离。
	故:
	dp[k][i][j] = min(dp[k-1][i][j], max(dp[k-1][i][k], dp[k-1][k][j]))
 
优化一下:
	dp[i][j] := min(dp[i][j], max(dp[i][k], dp[k][j]))
 
初始值:
	dp[0][i][j] := 从节点i到节点j的距离。
*/
  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstddef>
  5 #include <iterator>
  6 #include <algorithm>
  7 #include <string>
  8 #include <locale>
  9 #include <cmath>
 10 #include <vector>
 11 #include <cstring>
 12 #include <map>
 13 #include <utility>
 14 #include <queue>
 15 #include <stack>
 16 #include <set>
 17 using namespace std;
 18 const int INF = 0x3f3f3f3f;
 19 const int MaxN = 205;
 20 const int modPrime = 3046721;
 21 
 22 struct Node
 23 {
 24     double x, y;
 25 };
 26 
 27 int n;
 28 Node nodeSet[MaxN];
 29 double dp[MaxN][MaxN];
 30 double dis[MaxN][MaxN];
 31 
 32 void getDistance()
 33 {
 34     for (int i = 1; i <= n; ++i)
 35     {
 36         for (int j = 1; j <= n; ++j)
 37         {
 38             if (i != j)
 39             {    
 40                 dis[i][j] = sqrt((nodeSet[i].x - nodeSet[j].x)*(nodeSet[i].x - nodeSet[j].x) +
 41                                  (nodeSet[i].y - nodeSet[j].y)*(nodeSet[i].y - nodeSet[j].y));
 42                 dis[j][i] = dis[i][j];
 43             }
 44             else
 45             {
 46                 dis[i][j] = 0.0;
 47             }
 48         }
 49     }
 50 }
 51 
 52 void Solve()
 53 {
 54     for (int i = 1; i <= n; ++i)
 55     {
 56         for (int j = 1; j <= n; ++j)
 57         {
 58             dp[i][j] = dis[i][j];
 59         }
 60     }
 61     for (int k = 1; k <= n; ++k)
 62     {
 63         for (int i = 1; i <= n; ++i)
 64         {
 65             for (int j = 1; j <= n; ++j)
 66             {
 67                 dp[i][j] = min(dp[i][j], max(dp[i][k], dp[k][j]));
 68             }
 69         }
 70     }
 71     printf("Frog Distance = %.3lf\n\n", dp[1][2]);
 72 
 73 }
 74 
 75 int main()
 76 {
 77 #ifdef HOME
 78     freopen("in", "r", stdin);
 79     //freopen("out", "w", stdout);
 80 #endif
 81 
 82     int num = 1;
 83     while (~scanf("%d", &n) && n)
 84     {
 85         for (int i = 1; i <= n; ++i)
 86         {
 87             scanf("%lf %lf", &nodeSet[i].x, &nodeSet[i].y);
 88         }
 89         getDistance();
 90         printf("Scenario #%d\n", num);
 91         Solve();
 92         ++num;
 93     }
 94 
 95 
 96 #ifdef HOME
 97     cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
 98     _CrtDumpMemoryLeaks();
 99 #endif
100     return 0;
101 }
 
 

 


转载于:https://www.cnblogs.com/shijianming/p/5024111.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值