题意:求A到B的K短路!
分析:使用A*算法
所谓K短路,就是从s到t的第K短的路,第1短就是最短路。
如何求第K短呢?有一种简单的方法是广度优先搜索,记录t出队列的次数,当t第k次出队列时,就是第k短路了。但点数过大时,入队列的节点过多,时间和空间复杂度都较高。
A*是在搜索中常用的优化,一种启发式搜索。简单的说,它可以用公式表示为f(n) = g(n) + h(n),其中,f(n)是从s经由节点n到t的估价函数,g(n)是在状态空间中从s到n的实际代价,h(n)是从n到t的最佳路径估计代价。在设计中,要保证h(n)<= n到t的实际代价,这一点很重要,h(n)越接近真实值,速度越快。
由于启发函数的作用,使得计算机在进行状态转移时尽量避开不可能产生最优解的分支,而选择相对较接近最优解的路径进行搜索,降低了时间和空间复杂度。
算法过程:
1. 将图反向,用dijstra+heap求出t到所有点的最短距离,目的是求所有点到点t的最短路,用dis[i]表示i到t的最短路,其实这就是A*的启发函数,显然:h(n)<= n到t的实际代价。
2. 定义估价函数。我们定义g(n)为从s到n所花费的代价,h(n)为dis[n],显然这符合A*算法的要求。
3. 初始化状态。状态中存放当前到达的点i,fi,gi。显然,fi=gi+dis[i]。初始状态为(S,dis[S],0),存入优先级队列中。
4. 状态转移。假设当前状态所在的点v相邻的点u,我们可以得到转换:(V,fv,gv)-->(U,fu+w[v][u],gv+w[v][u])。
5. 终止条件。每个节点最多入队列K次,当t出队列K次时,即找到解。
// File Name: 10740.cpp // Author: Zlbing // Created Time: 2013/5/19 0:44:07 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=105; struct Edge{ int u,v,cost; }; vector<Edge> edges; vector<int> G[MAXN]; vector<Edge> O_edges; vector<int> O_G[MAXN]; int S,T,K; struct node{ int u; int f,g; bool operator <(const node& rhs)const{ return f>rhs.f; } }; int h[MAXN]; void dij(int t) { priority_queue<node> Q; CL(h,-1); Q.push((node){t,0,0}); while(!Q.empty()) { node tmp=Q.top(); Q.pop(); int u=tmp.u; int cost=tmp.f; if(h[u]!=-1)continue; h[u]=cost; for(int i=0;i<O_G[u].size();i++) { int mm=O_G[u][i]; Edge e=O_edges[mm]; tmp.u=e.v; tmp.f=e.cost+cost; Q.push(tmp); } } } int cnt[MAXN]; int a_star() { CL(cnt,0); priority_queue<node> Q; if(h[S]==-1)return -1; Q.push((node){S,h[S],0}); node t,tt; while(!Q.empty()) { t=Q.top(); Q.pop(); int u=t.u; int f=t.f; int g=t.g; cnt[u]++; if(cnt[T]==K)return g; if(cnt[u]>K)continue; for(int i=0;i<G[u].size();i++) { Edge e=edges[G[u][i]]; tt.u=e.v; tt.g=g+e.cost; tt.f=tt.g+h[tt.u]; Q.push(tt); } } return -1; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0)break; REP(i,0,n){ G[i].clear(); O_G[i].clear(); } edges.clear(); O_edges.clear(); scanf("%d%d%d",&S,&T,&K); int a,b,c; REP(i,1,m) { scanf("%d%d%d",&a,&b,&c); edges.push_back((Edge){a,b,c}); O_edges.push_back((Edge){b,a,c}); int mm=edges.size(); G[a].push_back(mm-1); O_G[b].push_back(mm-1); } dij(T); int ans=a_star(); printf("%d\n",ans); } return 0; }