Bellman-Ford和Floyd

还是最短路问题。
 
Dijkstra只能用在边权都为正的情况下。
  负权存在时有一种方法是Bellman-Ford:
  用d[i]存当前起点到i的的最短路,初始化d[0]=0,其他设为INF。假设总共n个点,最短路最多只经过n-1个点(起点不算)。所以我们可以通过n-1次循环确定起点到终点的最短路(第k次循环就能确定从起点经过k个节点的点的最短路,因为第k-1次循环确定后,第k次确定的最短路肯定是到起点有k-1个节点的点的最短路加上第那个点到这个点的距离)。
代码:
for(i=0;i<n;i++) d[i]=INF;
d[0]=0;
int k,i;
for(k=0;k<n-1;k++)
for(i=0;i<m;i++)   //共有m条边
{
      intx=u[i],y=v[i];    //u[i],v[i]是第i条边的起点,终点
      if(d[x]<INF)d[y]=d[y]<d[x]+w[i]?d[y]:d[x]+w[i];    //w[i]是第i条边的权值,松弛操作
}

  Bellman-Ford算法效率不高,可能要O(mn)时间。下面是Floyd:
  Floyd的思路是先计算最多经过第1个点从i到j的最短路(可以经过,也可以不经过),然后再计算最多经过第2个点从i到j的最短路(就是从i到j可以经过第1,第2个点,也可以经过其中一个,也可以都不经过)。。。。。。以此类推,直到第n个点,任何两个点之间的最短路就出来了。设d[i][j]为i到j的最短路,初始化d[i][i]=0,其他d值为INF,然后读入i,j,d[i][j]。
代码:
int i,j,k;
for(k=0;k<n;k++)   //k表示最多经过第k个点的最短路
for(i=0;i<n;i++)
for(j=0;j<n;j++)
  d[i][j]=d[i][j]<d[i][k]+d[k][j]?d[i][j]:d[i][k]+d[k][j];

注意别让d[i][k]+d[k][j]溢出。
如果只关心i到j有没有连通,设1为连通,0不连通,只要把d[i][j]=d[i][j]<d[i][k]+d[k][j]?d[i][j]:d[i][k]+d[k][j];改成d[i][j]=d[i][j]||d[i][k]&&d[k][j];

POJ 2253
Frogger
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 20243   Accepted: 6567

Description

Freddy Frog is sitting on astone in the middle of a lake. Suddenly he notices Fiona Frog whois sitting on another stone. He plans to visit her, but since thewater is dirty and full of tourists' sunscreen, he wants to avoidswimming and instead reach her by jumping.
Unfortunately Fiona's stone is out of his jump range. ThereforeFreddy considers to use other stones as intermediate stops andreach her by a sequence of several small jumps.
To execute a given sequence of jumps, a frog's jump range obviouslymust be at least as long as the longest jump occuring in thesequence.
The frog distance (humans also call it minimax distance) betweentwo stones therefore is defined as the minimum necessary jump rangeover all possible paths between the two stones.

You are given the coordinates of Freddy's stone, Fiona's stone andall other stones in the lake. Your job is to compute the frogdistance between Freddy's and Fiona's stone.

Input

The input will contain one ormore test cases. The first line of each test case will contain thenumber of stones n (2<=n<=200). Thenext n lines each contain two integers xi,yi (0 <=xi,yi <= 1000) representing the coordinates of stone#i. Stone #1 is Freddy's stone, stone #2 is Fiona's stone, theother n-2 stones are unoccupied. There's a blank line followingeach test case. Input is terminated by a value of zero (0) forn.

Output

For each test case, print a linesaying "Scenario #x" and a line saying "Frog Distance = y" where xis replaced by the test case number (they are numbered from 1) andy is replaced by the appropriate real number, printed to threedecimals. Put a blank line after each test case, even after thelast one.

Sample Input

2
0 0
3 4

3
17 4
19 4
18 5

0

Sample Output

Scenario #1
Frog Distance = 5.000

Scenario #2
Frog Distance = 1.414



  这道题意思是找出起点到终点路径上的一个最大边权,如果有多条路径,找出最大边权最小的那个。可以用Dijkstra也可以用Floyd。
  用Dijkstra的话用d[i]存到目前为止从起点到结点i符合条件的最小边权,每次循环在未标记的结点中找出d最小的结点标记,再用这一点去更新其他未标记的点。更新的代码是:
for(y=0;y<N;y++) d[y]=d[y]<max(d[x],map[x][y])?d[y]:max(d[x],map[x][y]); Dijkstra完整代码: 
#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

double map[210][210],d[210];

int vis[210],N,T=0;

double max(double a,double b)
{

    return a>b?a:b;
}

struct point
{

    int x,y;
} a[210];

double dis(double x1,double y1,double x2,double y2)
{

    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

void Dijkstra()
{

    memset(vis,0,sizeof(vis));

    int i;

    for(i=0; i<N; i++) d[i]=(i==0?0:10000000);

    for(i=0; i<N; i++)
    {

        int x,y,m=10000000;

        for(y=0; y<N; y++) if(d[y]<m&&!vis[y]) m=d[x=y];

        if(x==1) break;

        vis[x]=1;

        for(y=0; y<N; y++) d[y]=d[y]<max(d[x],map[x][y])?d[y]:max(d[x],map[x][y]);
    }
}



int main()
{

    while(scanf("%d",&N),N)
    {

        int i,j;

        for(i=0; i<N; i++) scanf("%d%d",&a[i].x,&a[i].y);

        for(i=0; i<N; i++)

            for(j=i; j<N; j++)

                map[i][j]=map[j][i]=dis(a[i].x,a[i].y,a[j].x,a[j].y);

        Dijkstra();

        printf("Scenario #%d\n",++T);

        printf("Frog Distance = %.3lf\n\n",d[1]);
    }

    return 0;
}

  如果用Folyd,设d[i][j]是从i到j的题目所求,关键在于如果d[i][j]比d[i][k]和d[k][j]都大,说明d[i][j]可以更新成一个更小的值了,变为min(d[i][k],d[k][j])。

Floyd完整代码:
#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

double map[210][210],d[210];

int vis[210],N,T=0;

double max(double a,double b)
{

    return a>b?a:b;
}

struct point
{

    int x,y;
} a[210];

double dis(double x1,double y1,double x2,double y2)
{

    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

void floyd()
{

    int i,j,k;

    for(k=0; k<N; k++)

        for(i=0; i<N; i++)

            for(j=0; j<N; j++)
            {

                if(map[i][j]>map[i][k]&&map[i][j]>map[k][j])

                    map[i][j]=max(map[i][k],map[k][j]);
            }
}



int main()
{

    while(scanf("%d",&N),N)
    {

        int i,j;

        for(i=0; i<N; i++) scanf("%d%d",&a[i].x,&a[i].y);

        for(i=0; i<N; i++)

            for(j=i; j<N; j++)

                map[i][j]=map[j][i]=dis(a[i].x,a[i].y,a[j].x,a[j].y);

        floyd();

        printf("Scenario #%d\n",++T);

        printf("Frog Distance = %.3lf\n\n",map[0][1]);
    }

    return 0;
}







你可能感兴趣的:(Bellman-Ford和Floyd)