toj1142 Frogger

题目链接:http://acm.tju.edu.cn/toj/showp1142.html

题目大意:求起点到终点,每次单跳都有个最小值,求出其中的最大值

思路:prim我想来是比较方便的,因为它的原理就是依次把相邻最短的加入到集合中,所以每次都可以找到到下一步的最小值,再从这些最小值中找到最大值。但又看到dijstra也可解,floyd也可解,然后就有点糊涂了,特意看了prim和dijstra的区别:转自: http://www.cnblogs.com/growup/archive/2010/11/13/1971536.html:

1.先说说prim算法的思想:

众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的点集合A,另一个集合为未加入生成树的点B,它的具体实现过程是:

第1步:所有的点都在集合B中,A集合为空。

第2步:任意以一个点为开始,把这个初始点加入集合A中,从集合B中减去这个点(代码实现很简单,也就是设置一个标示数组,为false表示这个点在B中,为true表示这个点在A中),寻找与它相邻的点中路径最短的点,如后把这个点也加入集合A中,从集合B中减去这个点(代码实现同上)。

第3步:集合A中已经有了多个点,这时两个集合A和B,只要找到A集合中的点到B集合中的点的最短边,可以是A集合中的与B集合中的点的任意组合,把这条最短边有两个顶点,把在集合B中的顶点加入到集合A中,(代码实现的时候有点技巧,不需要枚举所有情况,也就是更新操作)。

第4步:重复上述过程。一直到所有的点都在A集合中结束。

2.说说dijkstra算法的过程:

这个算法的过程有比prim算法的过程稍微多一点点步骤,但是思想确实巧妙的,也是贪心原理,它的目的是求某个源点到目的点的最短距离,总的来说,dijkstra算法也就是求某个源点到目的点的最短路,求解的过程也就是求源点到整个图的最短距离,次短距离,第三短距离等等(这些距离都是源点到某个点的最短距离)。。。。。求出来的每个距离都对应着一个点,也就是到这个点的最短距离,求的也就是原点到所有点的最短距离,并且存在了一个二维数组中,最后给出目的点就能直接通过查表获得最短距离。

第1步:以源点(假设是s1)为开始点,求最短距离,如何求呢? 与这个源点相邻的点与源点的距离全部放在一个数组dist[]中,如果不可达,dist[]中为最大值,这里说一下,为什么要是一维数组,原因是默认的是从源点到这个一维数组下标的值,只需要目的点作为下标就可以,这时从源点到其他点的最短的“一”条路径有了,只要选出dist[]中最小的就行(得到最短路径的另一个端点假设是s2)。

第2步:这时要寻找源点(假设是s1)到另外点的次短距离,这个距离或者是dist[]里面的值,或者是从第1步中选择的那个最短距离 + 从找到点(假设是s2)出发到其他点的距离(其实这里也是一个更新操作,更新的是dist[]里面的值),如果最短距离 + 从这点(假设是s2)到其他点的距离,小于dist[]里面的值,就可以更新dist[]数组了,然后再从dist[]数组中选一个值最小的,也就是第“二”短路径(次短路径)。

第3步:寻找第“三”短路径,这时同上,第二短路径的端点(s3)更新与之相邻其他的点的dist[]数组里面的值。

第4步:重复上述过程n - 1次(n指的是节点个数),得出结果,其实把源点到所有点的最短路径求出来了,都填在了dist[]表中,要找源点到哪个点的最短路,就只需要查表了。

转自:http://www.cnblogs.com/growup/archive/2010/11/13/1971536.htm

本题我还是用prim解起来比较顺手。。

代码:

#include<iostream>
#include<cmath>
#include<iomanip>
#include <cstring>
using namespace std;
const int  MAX = 3001;
int visited[205],i,j,n;
double dist[205],map[205][205];

struct node
{
    double x,y;       
}a[205];

double dis(double a1,double a2,double b1,double b2)
{
    return sqrt(double((a1-b1)*(a1-b1)+(a2-b2)*(a2-b2)));   //根号下:(x1-x2)的平方 +(y1-y2)的平方

}

double prim()    //同prim模板
{
    int pos;
    double ans,min;
    for(i=1;i<=n;i++)
    {
        dist[i]=map[1][i];                 
    }
    memset(visited,0,sizeof(visited));
    visited[1]=1;
    ans=0;//本题要求解的值 即各最小值中的最大值    
    for(i=1;i<=n-1;i++)
    {
        min=MAX;
        for(j=1;j<=n;j++)
        if(!visited[j]&&dist[j]<min)
        {
            pos=j;
            min=dist[j];                            
        }
        if(ans<min)ans=min;//找最小的中的最大的
        if(pos==2)break;   //终点              
        visited[pos]=1;
        for(j=1;j<=n;j++)//更新dist数组
            if(!visited[j]&&map[pos][j]<dist[j])
               dist[j]=map[pos][j];                  
    }
    return ans;   
}

int main()
{
    int num=1;
    while(cin>>n)
    {
       if(n==0)break;
       for(i=1;i<=n;i++)
       cin>>a[i].x>>a[i].y;
          
       for(i=1;i<=n;i++)
       for(j=1;j<=n;j++)
       map[i][j]=map[j][i]=dis(a[i].x,a[i].y,a[j].x,a[j].y);
       
       cout<<fixed<<setprecision(3);  // double小数点后3位!
       cout<<"Scenario #"<<num<<endl;
       cout<<"Frog Distance = "<<prim()<<endl<<endl;
       num++;         
    }
    return 0;   
}

附加:Floyd解法:转自http://www.cnblogs.com/jamespan/archive/2012/02/01/2334394.html


#include<cstdio>
#include<cmath>
#define MAX(x,y)((x)>(y)?(x):(y))

struct Point
{
	double x,y;
	bool visited;
};

double distance(Point &a, Point &b)
{
	return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}

Point stone[210];
double dist[210][210];
int main()
{
	int n;
	int cases = 1;
	while((scanf("%d",&n)!=EOF)&& n)
	{
		for(int i=0;i<n;i++)
	{
		scanf("%lf%lf", &stone[i].x,&stone[i].y);
		stone[i].visited=false;
	}
	for(int i=0;i<n;i++)
	{
		for(int j=i;j<n;j++)
		{
			dist[j][i]=dist[i][j]=distance(stone[i],stone[j]);
		}
	}
	
	for(int k=0;k<n;k++)
	{
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				if(dist[i][j]>dist[i][k] && dist[i][j]>dist[j][k])
				{
					dist[i][j]=MAX(dist[i][k],dist[j][k]);
				}
			}
		}
	}
	
	printf("Scenario #%d\n", cases++);
	printf("Frog Distance = %.3f\n\n",dist[0][1]);
}
return 0;
}
	


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值