这里的第K短路的定义是:
1.如果起点终点相同,那么0并不是最短路,而是要出去一圈回来之后才是最短路,那么第K短路也是一样。
2.每个顶点和每条边都可以使用多次。(可以存在环和来回走)
然后求K短路使用A*算法,其估价函数f(n) = g(n)+h(n),h(n)是终点到结点n的最短路径,g(n)是起点到结点n的实际代价, 这样选择显然能满足A*估价函数的要求,g(n)>=g'(n),
h(n)<=h'(n)。
h(n)可以对原图的逆图进行SPFA得出。
终止条件是,如果终点第K次出队的话,那么表明已经找到第K短路。
注意处理起点终点不连通的情况。
很裸的K短路题。
传送门:http://poj.org/problem?id=2449
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<algorithm> using namespace std; const int MAXN = 1111,MAXM = 111111; struct edge{ int v,w,nxt; edge(){} edge(int vv,int ww):v(vv),w(ww){} }rst[MAXM<<1],sec[MAXM<<1]; struct node{ int f,g,v; node(){} node(int ff,int gg,int vv):f(ff),g(gg),v(vv){} bool operator < (const node &n) const{ return n.f<f; } }; int hrst[MAXN],hsec[MAXN],dist[MAXN],inQ[MAXN],n,m,s,t,k,ecnt; void init(){ memset(hrst,-1,sizeof(hrst)); memset(hsec,-1,sizeof(hsec)); ecnt = 0; fill(dist,dist+MAXN,0x3fffffff); memset(inQ,0,sizeof(inQ)); } void add(int u,int v,int w){ rst[ecnt] = edge(v,w); sec[ecnt] = edge(u,w); rst[ecnt].nxt = hrst[u]; sec[ecnt].nxt = hsec[v]; hrst[u] = ecnt; hsec[v] = ecnt++; } void SPFA(int src){ queue<int> Q; Q.push(src);inQ[src]=1; dist[src]=0; while(!Q.empty()){ int cur = Q.front(); Q.pop();inQ[cur]=0; for(int i=hsec[cur];i!=-1;i=sec[i].nxt){ if(dist[sec[i].v]>dist[cur]+sec[i].w){ dist[sec[i].v] = dist[cur]+sec[i].w; if(!inQ[sec[i].v])inQ[sec[i].v]=1,Q.push(sec[i].v); } } } } int Astar(int src,int dest){ priority_queue<node> PQ; if(dist[src]==0x3fffffff)return -1;//不可达 memset(inQ,0,sizeof(inQ)); PQ.push(node(dist[src],0,src)); while(!PQ.empty()){ node cur = PQ.top(); PQ.pop();inQ[cur.v]++; //cout<<cur.f<<" "<<cur.v<<" "<<dest<<" "<<inQ[dest]<<endl; if(inQ[dest]==k)return cur.f; if(inQ[cur.v]>k)continue;//don't process this case when a node out of queue more then k times for(int i=hrst[cur.v];i!=-1;i=rst[i].nxt){ node next(dist[rst[i].v]+rst[i].w+cur.g,cur.g+rst[i].w,rst[i].v); PQ.push(next);//expand new node; } } return -1; } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ init(); while(m--){ int a,b,c; scanf("%d%d%d",&a,&b,&c);a--,b--; add(a,b,c); } scanf("%d%d%d",&s,&t,&k);s--,t--; SPFA(t); if(s==t)k++;//如果起点终点相同,0不是第1短路径。。 printf("%d\n",Astar(s,t)); } return 0; }