题目链接: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; }