• POJ 2499 A*求第K短路


    DES就是给你一个图。然后给你起点和终点。问你从起点到终点的第K短路。

    第一次接触A*算法。

    题目链接:Remmarguts' Date

    转载:http://blog.csdn.net/mbxc816/article/details/7197228#plain

    // 大概懂思路了。A*算法需要的估价函数里的两个函数、一个是起点到当前点的消耗。
    //一个是当前点到目标点的估测消耗。所以需要用Dijstra或者Spfa求出目标点到所有点的最短路。
    //然后就可以用A*算法来求了。
    // 确实。学了位运算。链式表。
    
    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<string.h>
    #define maxn 1005
    #define maxm 200100
    using namespace std;
    
    struct Node{
      int v, c, n, nxt;
    }Edge[maxm];
    
    int head[maxn];
    int tail[maxn];
    int h[maxn];
    
    struct Statement {
       int v, d, h;
       bool operator < (Statement a) const {
         return a.d+a.h<d+h;
       }
    };
    
    void addEdge (int u, int v, int c, int e)
    {
        Edge[e<<1].v = v;
        Edge[e<<1].c = c;
        Edge[e<<1].nxt = head[u];
        head[u] = e<<1; // A*算法对周边的店扩展时按是从1到n;
    
        // 任意数|1相当于给这个数+1。
        Edge[e<<1|1].v = u;
        Edge[e<<1|1].c = c;
        Edge[e<<1|1].nxt = tail[v];
        tail[v] = e<<1|1; // Dijstra求最短路时、改为求t到其它所有节点的单源最短路
        return;
    }
    
    void Dijstra (int n, int s, int t)
    {
        bool vis[maxn];
        memset(vis, 0, sizeof(vis));
        memset(h, 0x7F, sizeof(h));
        h[t] = 0;
        for (int i=1; i<=n; ++i) {
            int min = 0x7FFF;
            int k = -1;
            for (int j=1; j<=n; ++j) {
                if (vis[j] == false && min>h[j])
                    min = h[j], k = j;
            }
            if (k == -1) break;
            vis[k] = true;
            for (int temp=tail[k]; temp != -1; temp=Edge[temp].nxt) {
                int v = Edge[temp].v;
                if (h[v] > h[k]+Edge[temp].c)
                    h[v]=h[k]+Edge[temp].c;
            }
        }
    }
    
    int Astar_Kth (int n, int s, int t, int k)
    {
        Statement cur, nxt;
        priority_queue<Statement>FstQ;
    
        int cnt[maxn];
        memset(cnt, 0, sizeof(cnt));
        cur.v = s; // 开启列表的第一个点、当前移动耗费和预估移动耗费。
        cur.d = 0;
        cur.h = h[s];
    
        FstQ.push(cur);
    
        while(!FstQ.empty()) {
            cur = FstQ.top();
            FstQ.pop();
    
            cnt[cur.v]++;  // cnt[] 表示当前节点被扩展了几次。如果大于k 显然不符合题意。
            if (cnt[cur.v] > k) continue;  // 某个节点的第X次扩展。就说明这是该节点的第X短路、。
            if (cnt[t] == k) return cur.d; // 如果目标节点刚好被扩展了k次。说明找到第K短路。结束寻路、
    
            for (int temp=head[cur.v]; temp!=-1; temp=Edge[temp].nxt) {
                int v = Edge[temp].v;
                nxt.d = cur.d + Edge[temp].c;
                nxt.v = v;
                nxt.h = h[v];
                FstQ.push(nxt);
            }
        }
        return -1;
    }
    
    int main()
    {
        int n, m;
        while(scanf("%d %d", &n, &m) != EOF) {
            int u, v, c;
            memset(head, -1, sizeof(head));
            memset(tail, -1, sizeof(tail));
    
            for (int i=0; i<m; ++i) {
                scanf("%d %d %d", &u, &v, &c);
                addEdge(u, v, c, i);
            }
    
            int s, t, k;
            scanf("%d %d %d", &s, &t, &k);
            if (s == t) k++;
            Dijstra(n, s, t);
            printf("%d
    ", Astar_Kth(n, s, t, k));
        }
        return 0;
    }
    View Code

      一天后。按照这个思路自己敲了一下。发现bug不止一点点。。而且有许多不懂的地方。主要因为不懂链表存储的原理、然后A*算法寻路的原理也很模糊。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<queue>
    using namespace std;
    
    #define maxn 1005
    #define maxm 200100
    
    struct Node {  // 单源最短路径准备
       int v, c, nxt;
    }Edge[maxm];
    
    int head[maxn];
    int tail[maxn];
    int h[maxn]; // 保存目标节点到每个点的最短路径
    
    struct Statement {  // 保存每个节点的估价函数的两个函数。和相连的下一个节点。
        int v, d, h;
        bool operator < (Statement a) const {  // 优先队列重载< 符号。
            return a.d+a.h < d+h;
        }
    };
    
    void addEdge (int u, int v, int c, int i)
    {
        Edge[i<<1].v = v;
        Edge[i<<1].c = c;
        Edge[i<<1].nxt = head[u];
        head[u] = i<<1;
    
        Edge[i<<1|1].v = u;
        Edge[i<<1|1].c = c;
        Edge[i<<1|1].nxt = tail[v];
        tail[v] = i<<1|1;
        return;
    }
    
    void Dijstra (int n, int s, int t)
    {
         bool vis[maxn];
         memset(vis, 0, sizeof(vis));
         memset(h, 0x7f, sizeof(h));
    
         // 刚开始写成了h[s] = 0.。。但是这是以t为源点求单源最短路径。所以。应该初始化为h[t] = 0;
         h[t] = 0;
         for (int i=1; i<=n; ++i) {
            int minn = 0x7f;
            int k = -1;
            for (int j=1; j<=n; ++j) {
                if (minn > h[j] && vis[j] == false) {
                    k = j;
                    minn = h[j];
                }
            }
            if (k == -1) break;
            vis[k] = true;
            // 这里不是很理解。因为不懂链表的存储结构。
            for (int temp=tail[k]; temp!=-1; temp=Edge[temp].nxt) {
                int v = Edge[temp].v;
                if (h[v] > Edge[temp].c + h[k])
                    h[v] = Edge[temp].c + h[k];
            }
         }
    }
    
    int Astar_kth (int n, int s, int t, int k)
    {
        Statement cur, nxt;
        priority_queue<Statement>FstQ;
    
        int cnt[maxn];
        memset(cnt, 0, sizeof(cnt));
        cur.v = s;
        cur.d = 0;
        cur.h = h[s];
    
        FstQ.push(cur);
        while(!FstQ.empty()) {
         cur = FstQ.top();
         FstQ.pop();
         cnt[cur.v]++;
    
         //突然发现不太懂A*算法了。当前节点的扩展次数就是当前节点的第几短路。???
         if (cnt[cur.v] > k) continue;
         if (cnt[t] == k) return cur.d;
    
         //这里也不太懂。就是链表的问题。
         for (int temp=head[cur.v]; temp!=-1; temp=Edge[temp].nxt) {
            int v = Edge[temp].v;
            nxt.d = cur.d+Edge[temp].c; // 走过的可以再走。没有限制。所以每次搜到的新节点的消耗 就是前一个节点已消耗的加上到当前节点的消耗。
            nxt.v = v;
            nxt.h = h[v];
            FstQ.push(nxt);
         }
        }
        return -1;
    }
    
    int main()
    {
        int n, m;
        while(~scanf("%d%d", &n, &m)) {
            memset(head, -1, sizeof(head));
            memset(tail, -1, sizeof(tail));
    
            for (int i=0; i<m; ++i) {
                int a, b, t;
                scanf("%d%d%d", &a, &b, &t);
                addEdge(a, b, t, i);
            }
            int s, t, k;
            scanf("%d%d%d", &s, &t, &k);
            if (s == t) k++;  // s == t 时 貌似不能把0算作一条最短路。所以k++。
            Dijstra(n, s, t);
            int ans = Astar_kth(n, s, t, k);
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    linux查看文件有多少行(WC)
    MYSQL -- 联合索引
    MySQL -- 调优
    MySQL
    Linux命令执行的屏幕输出内容重定向到日志文件
    golang日期时间格式format()
    scp遇到路径中有空格
    查看服务器的网络吞吐
    SQL中关于where后面不能放聚合函数(如sum等)的解决办法
    gearman kubernetes 运行
  • 原文地址:https://www.cnblogs.com/icode-girl/p/4777002.html
Copyright © 2020-2023  润新知