zoukankan      html  css  js  c++  java
  • POJ 2387 Til the Cows Come Home(最短路板子题,Dijkstra算法, spfa算法,Floyd算法,深搜DFS)

    Til the Cows Come Home

    Time Limit: 1000MS Memory Limit: 65536K
    Total Submissions: 43861 Accepted: 14902

    Description

    Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the morning milking. Bessie needs her beauty sleep, so she wants to get back as quickly as possible.

    Farmer John's field has N (2 <= N <= 1000) landmarks in it, uniquely numbered 1..N. Landmark 1 is the barn; the apple tree grove in which Bessie stands all day is landmark N. Cows travel in the field using T (1 <= T <= 2000) bidirectional cow-trails of various lengths between the landmarks. Bessie is not confident of her navigation ability, so she always stays on a trail from its start to its end once she starts it.

    Given the trails between the landmarks, determine the minimum distance Bessie must walk to get back to the barn. It is guaranteed that some such route exists.

    Input

    * Line 1: Two integers: T and N

    * Lines 2..T+1: Each line describes a trail as three space-separated integers. The first two integers are the landmarks between which the trail travels. The third integer is the length of the trail, range 1..100.

    Output

    * Line 1: A single integer, the minimum distance that Bessie must travel to get from landmark N to landmark 1.

    Sample Input

    5 5
    1 2 20
    2 3 30
    3 4 20
    4 5 20
    1 5 100
    

    Sample Output

    90
    

    Hint

    INPUT DETAILS:

    There are five landmarks.

    OUTPUT DETAILS:

    Bessie can get home by following trails 4, 3, 2, and 1.

    思路:

    经典最短路径板子题(模板题)

    现在用 Dijkstra算法, spfa(bellman ford)算法, Floyd算法, 深搜DFS都写一遍回顾下

    递归DFS(TLE)

    使用快读(代码未写出)以后仍T,说明DFS做了很多无用的搜索,在优化搜索的程度上可以进阶学习A*搜索算法

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    #define ms(a,b) memset(a,b,sizeof(b));
    
    const int inf = 0x3f3f3f3f;
    const int N = 1000 + 10;
    int map[N][N];
    bool book[N];
    int minn , n;
    
    void dfs(int index,int step) {
        if (index == 1) {
            minn = min(minn, step);
            return;
        }
        if (step > minn)return;
        for (int i = 1; i <= n; ++i) {
            if (!book[i] && map[index][i] != inf) {
                book[i] = 1;
                dfs(i, step + map[index][i]);
                book[i] = 0;
            }
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int t, t1, t2, w;
        while (cin >> t >> n) {
            minn = inf;
            ms(map,inf);
            ms(book,false);
            //memset(map, inf, sizeof(map));
            //memset(book, false, sizeof(book));
    
            while (t--) {
                cin >> t1 >> t2 >> w;
                map[t1][t2] = map[t2][t1] = min(map[t1][t2], w);
            }
            book[n] = 1;
            dfs(n, 0);
            cout << minn << endl;
        }
        return 0;
    }
    

    dijkstra算法(AC 、79ms)

    #include <stdio.h>
    #include <string.h>
    #include <string>
    #include <iostream>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    const int inf=1<<29;
    int map[1010][1010];//map[i][j]表示从i-->j的距离  
    int dist[1010];//dist[i]从v1到i的距离  
    int vis[1010];//标记有没有被访问过  
    void dijkstra(int n)
    {
        int k,min;
        for(int i=1; i<=n; i++)
        {
            dist[i]=map[1][i];
            vis[i]=0;
        }
        for(int i=1; i<=n; i++)//遍历顶点  
        {
            k=0;
            min=inf;
            for(int j=1; j<=n; j++)
                if(vis[j]==0&&dist[j]<min)
                {
                    min=dist[j];
                    k=j;
                }
            vis[k]=1;
            for(int j=1; j<=n; j++)
                if(vis[j]==0&&dist[k]+map[k][j]<dist[j])
                    dist[j]=dist[k]+map[k][j];//如果找到了通路就加上 
        }
        return;
    }
    int main()
    {
        int t,n,a,b,w;
        while(~scanf("%d%d",&t,&n))
        {
            mem(map,0);
            mem(vis,0);
            mem(dist,0);
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    map[i][j]=inf;//初始化为无穷大  
            for(int i=1; i<=t; i++)
            {
                scanf("%d%d%d",&a,&b,&w);
                if(w<map[a][b])
                {
                    map[a][b]=w;
                    map[b][a]=map[a][b];//建立无向图
                }//这里是判断是否有重边,应为两点之间的路,未必只有一条。
            }
            dijkstra(n);
            printf("%d
    ",dist[n]);
        }
        return 0;
    }
    

    堆优化:

    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    #include <cmath>
    #include <deque>
    #include <vector>
    #include <queue>
    #include <string>1
    #include <cstring>
    #include <map>
    #include <stack>
    #include <set>
    #include <sstream>
    #define IOS ios_base::sync_with_stdio(0); cin.tie(0)
    #define Mod 1000000007
    #define eps 1e-6
    #define ll long long
    #define INF 0x3f3f3f3f
    #define MEM(x,y) memset(x,y,sizeof(x))
    #define Maxn 2000+5
    #define P pair<int,int>//first最短路径second顶点编号
    using namespace std;
    int N, M, X;
    struct edge
    {
        int to, cost;
        edge(int to, int cost) :to(to), cost(cost) {}
    };
    vector<edge>G[Maxn];//G[i] 从i到G[i].to的距离为cost
    int d[Maxn][Maxn];//d[i][j]从i到j的最短距离
    void Dijk(int s)
    {
        priority_queue<P, vector<P>, greater<P> >q;//按first从小到大出队
        for (int i = 0; i <= M; i++)
            d[s][i] = INF;
        d[s][s] = 0;
        q.push(P(0, s));
        while (!q.empty())
        {
            P p = q.top();
            q.pop();
            int v = p.second;//点v
            if (d[s][v] < p.first)
                continue;
            for (int i = 0; i < G[v].size(); i++)
            {
                edge e = G[v][i];//枚举与v相邻的点
                if (d[s][e.to] > d[s][v] + e.cost)
                {
                    d[s][e.to] = d[s][v] + e.cost;
                    q.push(P(d[s][e.to], e.to));
                }
            }
        }
    }
    int main()
    {
        IOS;
        while (cin >> N >> M)
        {
            for (int i = 0; i < N; i++)
            {
                int x, y, z;
                cin >> x >> y >> z;
                G[x].push_back(edge(y, z));
                G[y].push_back(edge(x, z));
            }
            Dijk(1);
            cout << d[1][M] << endl;
        }
        return 0;
    }
    

    floyd算法(TLE)

    #include<cstring>
    #include <iostream>
    #include <algorithm>
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    const int inf = 1 << 29;
    int map[1010][1010];//map[i][j]表示从i-->j的距离
    int main()
    {
        int t, n, a, b, w;
        while (~scanf("%d%d", &t, &n))
        {
            mem(map, 0);
            //初始化
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    if (i == j)
                        map[i][j] = 0;
                    else
                        map[i][j] = inf;//初始化为无穷大
            //建立图
            for (int i = 1; i <= t; i++){
                scanf("%d%d%d", &a, &b, &w);
                map[a][b] = map[b][a] = min(w, map[a][b]);//建立无向图
            }//这里是判断是否有重边,应为两点之间的路,未必只有一条。
            //弗洛伊德(Floyd)核心语句
            for (int k = 1; k <= n; k++)
                for (int i = 1; i <= n; i++)
                    for (int j = 1; j <= n; j++)
                        if (map[i][k] + map[k][j] < map[i][j])
                            map[i][j] = map[i][k] + map[k][j];
            printf("%d
    ", map[1][n]);
        }
        return 0;
    }
    

    Bellman ford算法(AC 496ms。。)

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstdio>
    typedef long long ll;
    //typedef unsigned long long ull;
    using namespace std;
    
    const int N = 1005, T = 4005;
    int n, t;
    int dis[N];
    vector<vector<int> > gra(T, vector<int> (3)); //邻接表存储图
    const int inf = 1 << 29;
    
    void bellmanford() {
        for (int i = 1; i <= n; ++i) {
            dis[i] = inf;
        }
        dis[1] = 0;
        for (int i = 1; i < n; ++i) {
            for (int j = 1; j <= t * 2; ++j) {
                dis[gra[j][1]] = min(dis[gra[j][1]], dis[gra[j][0]] + gra[j][2]);
            }
        }
    }
    
    
    int main() {
        scanf("%d%d", &t, &n);
        for (int i = 0, index = 1; i < t; ++i) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            gra[index][0] = a, gra[index][1] = b, gra[index][2] = c; ++index;
            gra[index][1] = a, gra[index][0] = b, gra[index][2] = c; ++index;
        }
        bellmanford();
        printf("%d
    ", dis[n]);
        return 0;
    }
    
    

    spfa队列优化(bfs、AC 79ms)

    //spfa
    #include <vector>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    using namespace std;
    const int N = 1005, T = 4005;
    int n, t;
    int dis[N], vis[N];  //dis数组存单元源点到其他各个点的距离
    //vis存顶点v是否已经在队列当中以减少不必要的操作
    vector<int> to[N], edge[N]; //邻接表分别存以i为下标的邻接的顶点和权值
    const int inf = 1 << 29;
    
    void spfa() {
        queue<int> q;
        for (int i = 1; i <= n; ++i) {
            dis[i] = inf;
        }
        dis[1] = 0;
        q.push(1);
        while (!q.empty()) {
            int u = q.front(); q.pop();
            vis[u] = false;
            for (int i = 0; i < to[u].size(); ++i) { //遍历邻接的顶点
                int v = to[u][i], w = edge[u][i];
                if (dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    if (!vis[v]) {
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
    }
    
    
    int main() {
        scanf("%d%d", &t, &n);
        for (int i = 0; i < t; ++i) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            //无向图
            to[a].push_back(b); edge[a].push_back(c);
            to[b].push_back(a); edge[b].push_back(c);
        }
        spfa();
        printf("%d
    ", dis[n]);
        return 0;
    }
    
    

    写完几种模板以后分析一下时间复杂度

    参考资料

    • 资料出自《啊哈算法》
  • 相关阅读:
    缩水版遗传算法 学习笔记
    算法导论 二项堆
    Linux系统编程(6)——文件系统
    Linux系统编程(5)——文件与IO之mmap函数
    Linux系统编程(4)——文件与IO之ioctl函数
    Linux系统编程(3)——文件与IO之fcntl函数
    Linux系统编程(2)——文件与IO之系统调用与文件IO操作
    Linux系统编程(1)——文件与I/O之C标准I/O函数与系统调用I/O
    C语言的本质(38)——makefile之变量
    C语言的本质(37)——makefile之隐含规则和模式规则
  • 原文地址:https://www.cnblogs.com/RioTian/p/12879353.html
Copyright © 2011-2022 走看看