【A*/K短路】 [USACO08MAR]Cow Jogging G

P2901 [USACO08MAR]Cow Jogging G

思路:先反向建边求各点到节点1的最短路,再A*依次得到节点\(n\)到节点\(1\)的第\(k\)短路。

总体来说就是改进版的BFS,在BFS的基础上另外设定了一个估价函数作为节点出队顺序的依据,而不像BFS那样先入队者先出队。在本题中,估价最小的节点会被优先拓展,然后是次小的、更小的……每次拓展到终点\(1\)时,都形成一条通路,越先形成的通路越短。

const int INF = 0x3f3f3f3f;
const int maxn = 1e4 + 100;

inline int read() {
    int X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    return w ? -X : X;
}

int n, m, k;
int d[1100];
//各点到池塘的距离
bool done[1100];
int ahead[1100], anum = 0;
int head[1100], num = 0;

struct Edge {
    int next, to, dis;
}ae[maxn],e[maxn];

struct Heapnode {
    int u, dis;
    bool operator < (const Heapnode& t) const {
        return dis > t.dis;
    }
    Heapnode(int from, int d) :u(from), dis(d) {}
};

struct node {
    int pos, dis;
    //dis为 起点到pos的最短距离
    bool operator <(const node& t)const {
        return dis + d[pos] > t.dis + d[t.pos];
        //加上点pos到终点的估计距离来比较,总估值最小的优先
    }
    node(int u, int d) :pos(u), dis(d) {}
};

void addedge1(int from, int to, int dis) {
    anum++;
    ae[anum].next = ahead[from];
    ae[anum].to = to;
    ae[anum].dis = dis;
    ahead[from] = anum;
}

void addedge2(int from, int to, int dis) {
    num++;
    e[num].next = head[from];
    e[num].to = to;
    e[num].dis = dis;
    head[from] = num;
}

void dij(int s) {
    priority_queue<Heapnode> pq;
    d[s] = 0;
    pq.push(Heapnode(s,d[s]));
    while (pq.size()) {
        Heapnode tmp = pq.top(); pq.pop();
        int u = tmp.u;
        if (done[u]) continue;
        for (int i = ahead[u]; i; i = ae[i].next) {
            if (d[u] + ae[i].dis < d[ae[i].to]) {
                d[ae[i].to] = d[u] + ae[i].dis;
                pq.push(Heapnode(ae[i].to, d[ae[i].to]));
            }
        }
        done[u] = true;
    }
}

int Astar(int k) {
    priority_queue<node> Q;
    Q.push(node(n, 0));
    while (Q.size()) {
        int u = Q.top().pos;
        int dis = Q.top().dis;
        Q.pop();
        //取到终点
        if (u == 1) {
            k--;
            cout << dis << endl;
            if (!k) return 0;
            //前k短路已经全部求出
        }
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].to, w = e[i].dis;
            Q.push(node(v, w + dis));
            //w是点u到点v的距离 
            //dis是起点到点u的距离
            //w+dis是起点到点v的距离
        }
    }
    //要计算前k短路,但可能只能算出前a短路,剩下的不存在
    //优先队列为空时能计算的前a短路已经算完
    //剩下的k-a行只能输出-1
    return k;
}


int main() {
    n = read();m = read();k = read();
    memset(d, INF, sizeof(d));
    memset(done, false, sizeof(done));
    for (int i = 1; i <= m; i++) {
        int u, v, dis;
        u = read(); v = read(); dis = read();
        addedge1(v, u, dis);
        //反向建边存图来求各点到终点的最短路
        addedge2(u, v, dis);
        //正常建边存图来Astar
        //注意别存成了双向边
    }
    dij(1);
    int last = Astar(k);
    while (last--) cout << -1 << endl;
    return 0;
}
posted @ 2020-09-22 17:54  StreamAzure  阅读(213)  评论(0)    收藏  举报