[KuangBin最短路专题]POJ-2253-Frogger

最短路的两种变形

原题链接:传送门

题目大意

给定一个图,求出图中给定起点到终点的所有路径中,最长的那条边最小为多少?但是有几点特殊的情况需要处理:

  • 题目给定的是二维坐标系的坐标形式,你需要自己求出来这些点之间的权值进行加边
  • 对于权值的精度需处理要小心

分析

对于图论题目重要的过程在于分析和建模,如何能够解析出题意正确建图是很关键的一个环节。

对于此题,首先肯定排除求出所有的路径,再依次遍历所有路径的做法,时间复杂度不符合题目预设。

那么我们尝试只用一次遍历来解决这个问题。

通过分析我们发现题目中固定了起点和终点,这种模式和最短路算法比较相近,我们考虑如何能够使用最短路的方法来求解此问题。

我们将最短路径中表示记录起点到某个点的距离的数组给改变一下,dis[x] 表示 从起点开始到x点的路径中最长的那条边中最短的边的权值

于是我们更新dis[y] 有以下方式:

\(dis[y] = min(dis[y] , max(dis[x] , w(x , y)))\)

void dijkstra(int s)
{
	for(int i = 1;i <= n ;i ++)dis[i] = 999999.0;
	memset(vis , 0 , sizeof vis);
	dis[s] = 0;
	for(int j = 0;j < n ;j ++)
	{
		int x = -1;
		for(int i = 1;i <= n ;i ++)
		{
			if(!vis[i] && (x == -1 || dis[i] < dis[x]))x = i;
		}
		vis[x] = 1;
		for(int i = head[x] ; i != -1 ;i = e[i].next)
		{
			int y = e[i].to;
			dis[y] = min(dis[y] , max(e[i].w , dis[x]));
		}
	}
}

注意事项

  • 对于输出需要用%.3f
  • 提交需要用C++ 看巨巨们的博客说是精度问题

AC 代码

C++ code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>

using namespace std;

const int N = 505;;
const int M = 50005;

struct edge{
	int to , next;
	double w;
}e[M];

int head[N] , tot , vis[N] , test;
double dis[N]; // dis[i]标识从1出发到达该点的所有边中的最大边
void add(int a,int b,double c)
{
	e[++tot].to = b;
	e[tot].w = c;
	e[tot].next = head[a];
	head[a] = tot;
}	
int n;
struct node{
	int x , y;
	node(int a,int b):x(a) , y(b){}
};

double getdis(int a,int b,int c,int d)
{
	return sqrt(double((a - c) * (a - c)) + double((b - d) * (b - d)));
}
void dijkstra(int s)
{
	for(int i = 1;i <= n ;i ++)dis[i] = 999999.0;
	memset(vis , 0 , sizeof vis);
	dis[s] = 0;
	for(int j = 0;j < n ;j ++)
	{
		int x = -1;
		for(int i = 1;i <= n ;i ++)
		{
			if(!vis[i] && (x == -1 || dis[i] < dis[x]))x = i;
		}
		vis[x] = 1;
		for(int i = head[x] ; i != -1 ;i = e[i].next)
		{
			int y = e[i].to;
			dis[y] = min(dis[y] , max(e[i].w , dis[x]));
		}
	}
}
void slove()
{
	tot = 0;
	memset(head , -1 , sizeof head);
	vector<node> v;
	for(int i = 0;i < n ;i ++)
	{
		int x, y ;cin >> x >> y;
		v.push_back(node(x , y));
	}
	for(int i = 0;i < v.size() ;i ++)
	{
		for(int j = i + 1;j < v.size() ;j ++)
		{
			double dis = getdis(v[i].x , v[i].y , v[j].x ,v[j].y);
			//printf("%d -> %d %f\n",i + 1 , j + 1 , dis );
			add(i + 1,j + 1, dis);
			add(j + 1,i + 1, dis);
		}
	}
	dijkstra(1);
	printf("Scenario #%d\n", test);
	printf("Frog Distance = %.3f\n\n", dis[2]);
}
int main()
{
	while(cin >> n && n)
	{
		test++;
		slove();
	}
	return 0;
}

启发

此类问题是最短路问题的一类变形问题,即虽然固定了起点和终点,但是却并不是让我们直接去求解两点之间的最短路径长度,而是所有从起点通向终点的路径中最长的那一条的最小值,当然我们也可以对此问题在进行变形。

例如求解所有路径中最小值边的最大值(POJ-1797)呀等等变形。

那么我们就要从最短路的意义出发,思考为什么最短路可以解决此类问题

posted @ 2020-09-27 23:10  _starsky  阅读(114)  评论(0编辑  收藏  举报