Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 19745 | Accepted: 5374 |
Description
Input
Output
Sample Input
2 2 1 2 5 2 1 4 1 2 2
Sample Output
14
思路:
K短路 A* + SPFA 版(邻接表);
使用SPFA以终点为起点根据逆向图求最短路,作为A*启发函数中的估价函数;
A*启发式搜索,其启发函数为 f[p] = g[p] +h[p]; h[p]为搜索至此的代价,g[p]是为估价函数(估计当前点到目标点的最小代价),估价函数要小于是对当前点到目标的代价的实际值,否则会出错!
需要注意的是,题目要求必须要走,所以当S==T时,K++;这样可以消除最短路为0的情况!
此处用一个ct[]数组保存每个点出队的次数,当目标节点出队K次时,它的len就是K短路的结果了。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> #include <queue> #define N 1010 #define M 100100 #define INF 0x7fffffff using namespace std; int dis[N]; // SPFA bool visit[N]; struct Edge{ // 用于构建邻接表 int to; int len; int next; // 类似链表next指针 }; struct Node{ int to; int len; bool operator<(const Node &a)const { // f(i)=d[i]+g[i] return len + dis[to] > a.len + dis[a.to]; } }; int S, T, K, e_num; Edge edge[M], reedge[M]; int head[N], rehead[N]; int ct[N]; void insert(int u, int v, int len) { edge[e_num].to = v; // 建立正向图 edge[e_num].len = len; edge[e_num].next = head[u]; head[u] = e_num; reedge[e_num].to = u; // 建立逆向图 reedge[e_num].len = len; reedge[e_num].next = rehead[v]; rehead[v] = e_num; e_num ++; } void Init() { memset(ct, 0, sizeof(ct)); memset(head, -1, sizeof(head)); memset(rehead, -1, sizeof(rehead)); e_num = 0; } void SPFA(int n) // 以终点为起点根据逆向图求最短路,用作A*的估价函数,结果保存到dis数组 { int i; queue<int>q; for(i = 1; i <= n; i++) dis[i] = INF; q.push(T); dis[T] = 0; visit[T] = 1; while(!q.empty()){ int cur = q.front(); q.pop(); visit[cur] = 0; for(i = rehead[cur]; i != -1; i = reedge[i].next){ // 遍历以cur为起点的所有边 int v = reedge[i].to; int len = reedge[i].len; if(dis[v] > dis[cur] + len){ dis[v] = dis[cur] + len; if(!visit[v]){ q.push(v); visit[v] = 1; } } } } } int A_star() // A*算法 { if(S == T) // 起点终点相等时,题目要求必须要走动,所以K应加1,消除最短路为0的情况 K ++; if(dis[S] == INF) // 路径不通的情况 return -1; Node nw; // 起点 nw.to = S; nw.len = 0; priority_queue <Node> q; q.push(nw); while(!q.empty()){ Node cur = q.top(); q.pop(); ct[cur.to] ++; // 计数 if(ct[T] == K) // 当第K次取到T的时候,输出路程 return cur.len; for(int i = head[cur.to]; i != -1; i = edge[i].next){ nw.to = edge[i].to; nw.len = edge[i].len + cur.len; q.push(nw); } } return -1; } int main() { int p_e_num, r_e_num, ct; int start, to, tm; Init(); scanf("%d%d", &p_e_num, &r_e_num); while(r_e_num --){ scanf("%d%d%d", &start, &to, &tm); insert(start, to, tm); } scanf("%d%d%d", &S, &T, &K); // 从S出发, 第K次到达T SPFA(p_e_num); ct = A_star(); printf("%d\n", ct); return 0; }