Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 22226 | Accepted: 6023 |
Description
Input
Output
Sample Input
2 2 1 2 5 2 1 4 1 2 2
Sample Output
14
求第K短路,如果没有输出-1。
以前是听过A*,现在才学习了一下。
来自百度百科:
A*(A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法。估价值与实际值越接近,估价函数取得就越好。
公式表示为: f(n)=g(n)+h(n),
其中 f(n) 是从初始点经由节点n到目标点的估价函数,
g(n) 是在状态空间中从初始节点到n节点的实际代价,
h(n) 是从n到目标节点最佳路径的估计代价。
保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:
估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。并且如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行, 此时的搜索效率是最高的。
如果 估价值>实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。
说简单点就是每个点有个值f(n),在优先队列中f值小的优先搜索。f=g+h。这道题里g是起始点到当前点走的步数,取h为当前点到终点的最短路。
当h为0时就变成了BFS,也就是BFS是A*的一种特殊情况。
可以自己想一下,如果在最短路上走,f不会变大,所以更可能优先被搜索,效率就会高。
那么这道题先用dijkstra求出终点到其它点的最短路,然后用A*算法,对于每个点有g和h,加入优先队列,g+h小的优先。直到终点被加入优先队列K次。
注意如果起点和终点相同,K要加1。
#include<cstdio> #include<cstring> #include<algorithm> #include<string> #include<iostream> #include<queue> #include<map> using namespace std; typedef pair<int,int> pii; const int MAXN=1010; const int MAXM=25; const int MAXC=110; const int MAXNODE=100010; const int LOGMAXN=50; const int INF=0x3f3f3f3f; int N,M,S,E,K; int d[MAXN]; struct Point{ int u,d; bool operator < (const Point& rhs) const{ return d>rhs.d; } }; struct Edge{ int u,v,dist; }; struct Dijkstra{ int n; int vis[MAXN]; vector<int> G[MAXN]; vector<Edge> edges; void init(int n){ this->n=n; for(int i=0;i<n;i++) G[i].clear(); edges.clear(); } void add_edge(int u,int v,int dist){ edges.push_back((Edge){u,v,dist}); int m=edges.size()-1; G[u].push_back(m); } void dijkstra(){ priority_queue<Point> q; memset(d,INF,sizeof(d)); memset(vis,0,sizeof(vis)); d[E]=0; q.push((Point){E,0}); while(!q.empty()){ Point tmp=q.top(); q.pop(); int u=tmp.u; if(vis[u]) continue; vis[u]=1; int len=G[u].size(); for(int i=0;i<len;i++){ Edge& e=edges[G[u][i]]; if(d[u]+e.dist<d[e.v]){ d[e.v]=d[u]+e.dist; q.push((Point){e.v,d[e.v]}); } } } } }solver; struct Point2{ int u,g,h; bool operator < (const Point2& rhs) const{ return g+h>rhs.g+rhs.h; } }; struct Astar{ int n; int cnt[MAXN]; vector<int> G[MAXN]; vector<Edge> edges; void init(int n){ this->n-n; for(int i=0;i<n;i++) G[i].clear(); edges.clear(); } void add_edge(int u,int v,int dist){ edges.push_back((Edge){u,v,dist}); int m=edges.size()-1; G[u].push_back(m); } int astar(int S,int E,int K){ priority_queue<Point2> q; memset(cnt,0,sizeof(cnt)); if(d[S]==INF) return -1; q.push((Point2){S,0,d[S]}); while(!q.empty()){ Point2 tmp=q.top(); q.pop(); int u=tmp.u,g=tmp.g,h=tmp.h; cnt[u]++; if(u==E&&cnt[u]>=K) return g; if(cnt[u]>K) continue; int len=G[u].size(); for(int i=0;i<len;i++){ Edge& e=edges[G[u][i]]; if(d[e.v]!=INF) q.push((Point2){e.v,g+e.dist,d[e.v]}); } } return -1; } }solver2; int main(){ freopen("in.txt","r",stdin); while(scanf("%d%d",&N,&M)!=EOF){ solver.init(N+1); solver2.init(N+1); int u,v,dist; while(M--){ scanf("%d%d%d",&u,&v,&dist); solver.add_edge(v,u,dist); solver2.add_edge(u,v,dist); } scanf("%d%d%d",&S,&E,&K); if(S==E) K++; solver.dijkstra(); printf("%d\n",solver2.astar(S,E,K)); } return 0; }