Dijkstra和Floyd算法

北战南征 提交于 2019-12-28 11:34:23
两个算法区别不是很大,一个是处理单源最短路径,一个是处理多源最短路径。 先总结下Dijkstra算法。从若干个节点中,找每次最小的提取出来,看经过最小的点的路径到达终点是否比原来小,本质上是贪心的思想。 不多说,放代码。题目来自洛谷P1339

题目描述

The good folks in Texas are having a heatwave this summer. Their Texas Longhorn cows make for good eating but are not so adept at creating creamy delicious dairy products. Farmer John is leading the charge to deliver plenty of ice cold nutritious milk to Texas so the Texans will not suffer the heat too much.

FJ has studied the routes that can be used to move milk from Wisconsin to Texas. These routes have a total of T (1 <= T <= 2,500) towns conveniently numbered 1..T along the way (including the starting and ending towns). Each town (except the source and destination towns) is connected to at least two other towns by bidirectional roads that have some cost of traversal (owing to gasoline consumption, tolls, etc.). Consider this map of seven towns; town 5 is the

source of the milk and town 4 is its destination (bracketed integers represent costs to traverse the route):

                              [1]----1---[3]-
                             /               \
                      [3]---6---[4]---3--[3]--4
                     /               /       /|
                    5         --[3]--  --[2]- |
                     \       /        /       |
                      [5]---7---[2]--2---[3]---
                            |       /
                           [1]------

Traversing 5-6-3-4 requires spending 3 (5->6) + 4 (6->3) + 3 (3->4) = 10 total expenses.

Given a map of all the C (1 <= C <= 6,200) connections (described as two endpoints R1i and R2i (1 <= R1i <= T; 1 <= R2i <= T) and costs (1 <= Ci <= 1,000), find the smallest total expense to traverse from the starting town Ts (1 <= Ts <= T) to the destination town Te (1 <= Te <= T).

德克萨斯纯朴的民眾们这个夏天正在遭受巨大的热浪!!!他们的德克萨斯长角牛吃起来不错,可是他们并不是很擅长生產富含奶油的乳製品。Farmer John此时以先天下之忧而忧,后天下之乐而乐的精神,身先士卒地承担起向德克萨斯运送大量的营养冰凉的牛奶的重任,以减轻德克萨斯人忍受酷暑的痛苦。

FJ已经研究过可以把牛奶从威斯康星运送到德克萨斯州的路线。这些路线包括起始点和终点先一共经过T (1 <= T <= 2,500)个城镇,方便地标号為1到T。除了起点和终点外地每个城镇由两条双向道路连向至少两个其它地城镇。每条道路有一个通过费用(包括油费,过路费等等)。

给定一个地图,包含C (1 <= C <= 6,200)条直接连接2个城镇的道路。每条道路由道路的起点Rs,终点Re (1 <= Rs <= T; 1 <= Re <= T),和花费(1 <= Ci <= 1,000)组成。求从起始的城镇Ts (1 <= Ts <= T)到终点的城镇Te(1 <= Te <= T)最小的总费用。

输入输出格式

输入格式:

第一行: 4个由空格隔开的整数: T, C, Ts, Te

第2到第C+1行: 第i+1行描述第i条道路。有3个由空格隔开的整数: Rs, Re和Ci

输出格式:

一个单独的整数表示从Ts到Te的最小总费用。数据保证至少存在一条道路。

输入输出样例

输入样例#1: 复制
7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1
输出样例#1: 复制
7

说明

【样例说明】

5->6->1->4 (3 + 1 + 3)


#include <iostream>
#define INT_MAX 1000000007;
using namespace std;
struct lucheng{
    int value;
    int visit;
}dis[10000];
int  arc[2510][2510];
int main(){
    int t,c,ts,te;
    cin>>t>>c>>ts>>te;
    int temp=c;
    for(int i=1;i<=t;i++){
        for(int j=1;j<=t;j++){
            arc[i][j]=INT_MAX;
        }
    }
    while(temp--){
        int start,end,value;
        cin>>start>>end>>value;
        arc[start][end]=value;
        arc[end][start]=value;
    }


    for(int i=1;i<=t;i++){
        dis[i].value=arc[ts][i];
    }
    dis[ts].value=0;
    dis[ts].visit=1;

    int count=1;

    while(count!=t){
        int tmp=0;
        int min=INT_MAX;

        for(int i=1;i<=t;i++){
            if(!dis[i].visit&&dis[i].value<min){
                min=dis[i].value;
                tmp=i;
            }
        }

        dis[tmp].visit=1;
        ++count; 

        for(int i=1;i<=t;i++){

            if (!dis[i].visit &&arc[tmp][i]!=1000000007&& dis[tmp].value + arc[tmp][i]< dis[i].value) {
                dis[i].value = dis[tmp].value + arc[tmp][i];
            }
    }
    }
    cout<<dis[te].value<<endl;
}

下面是Floyd算法,看经过额外的点,是否比原来的小。直接三层for循环

#include <iostream>
#define INTMAX 1000000007;
using namespace std;
int map[2510][2510];
int main(){
    int t,c,ts,te;
    cin>>t>>c>>ts>>te;
    for(int i=1;i<=t;i++){
        for(int j=1;j<=t;j++){
            map[i][j]=INTMAX;
        }
    }
    while(c--){
        int start,end,value;
        cin>>start>>end>>value;
        map[start][end]=value;
        map[end][start]=value;
    }
    for(int i=1;i<=t;i++){
        for(int j=1;j<=t;j++){
            for(int k=1;k<=t;k++){
                if(map[i][k]+map[k][j]<map[i][j]){
                    map[i][j]=map[i][k]+map[k][j];
                }
            }
        }
    }
    cout<<map[ts][te];
}

上边那个三层for循环会超时,,,,接下来就是大神的优化了打表大法好,

    #include<iostream>
    using namespace std;
    const int MAXN=6200+5;
    const int INF=2e9;
    int u[MAXN],w[MAXN],v[MAXN],dis[2501],s,e,m,n;
    bool check;//这个变量可以让我们进行略微的优化
    int main()
    {
        cin>>m>>n>>s>>e;//m个点,n条边
        for(int i=1;i<=n;i++)
            cin>>u[i]>>v[i]>>w[i];
        for(int i=1;i<=m;i++)
            dis[i]=INF;
        dis[s]=0;//到起点的最短距离为0
        m--;//一共进行m-1次松弛,可以优化时间
        for(int j=1;j<=m;j++)
        {
            check=true;//每一次松弛将这个变量都给true
            for(int i=1;i<=n;i++)
            {
                if(dis[v[i]]>dis[u[i]]+w[i])
                {
                    dis[v[i]]=dis[u[i]]+w[i];
                    check=false;
                }
                if(dis[u[i]]>dis[v[i]]+w[i])
                {
                    dis[u[i]]=dis[v[i]]+w[i];
                    check=false;
}//如果dis在松弛中没有发生变化,直接结束(因为已经求出了最短路径啊)

            }                
            if(check)    break;
        }    
        cout<<dis[e];//输出
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!