zoukankan      html  css  js  c++  java
  • [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
    ",i + 1 , j + 1 , dis );
    			add(i + 1,j + 1, dis);
    			add(j + 1,i + 1, dis);
    		}
    	}
    	dijkstra(1);
    	printf("Scenario #%d
    ", test);
    	printf("Frog Distance = %.3f
    
    ", dis[2]);
    }
    int main()
    {
    	while(cin >> n && n)
    	{
    		test++;
    		slove();
    	}
    	return 0;
    }
    

    启发

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

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

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

  • 相关阅读:
    ORACLE分页SQL语句
    oracle中主键自增
    html5video初试牛刀api
    如何修改tomcat的端口号
    用Java来获取访问者真实的IP地址
    根据txt文件处理的方法总结
    CXF 做 webservice 简单例子demo
    java创建TXT文件并进行读、写、修改操作
    POJ1047 Round and Round We Go
    NYOJ305 表达式求值
  • 原文地址:https://www.cnblogs.com/wlw-x/p/13742431.html
Copyright © 2011-2022 走看看