一道给定图,求S->T的k短路,想了半天还是没想法,看了别人题解才懂得,先求反向图源点为t的最短路,我是用dij的优先队列写的。然后用对于正向图,利用ASTAR算法,
利用优先队列,估价函数为f[i]=w+d[i],意思就是,我走了一个距离w,还有最短d[i]距离再到k,满足d[i]<=实际代价,ASTAR算法成立,这样对于每个节点,把所有与之相邻的点,压入优先队列,这样访问到节点t第k次时为k短路,返回此时的w,里面一个剪纸,对于一个点访问了大于k次就直接continue,因为这样走下去,肯定为>k短路。
code:
#include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; int n,m,s,t,k,d[1010],find[1010],cnt[1010]; const int inf=999999999; struct node { int y,l; }; struct dij { int v,w; friend bool operator<(dij a,dij b) { return a.w>b.w; } }; struct aastar { int v,w; friend bool operator<(aastar a,aastar b) { return a.w+d[a.v]>b.w+d[b.v];} }; vector<node>vt[1010]; vector<node>rvt[1010]; void dijstra() { for(int i=1;i<=n;i++)d[i]=inf; d[t]=0; memset(find,0,sizeof(find)); priority_queue<dij>q; dij ss,tt; ss.v=t; ss.w=0; q.push(ss); while(!q.empty()) { ss=q.top(); q.pop(); int v=ss.v; int w=ss.w; find[v]=1; for(int i=0;i<rvt[v].size();i++) { int y=rvt[v][i].y; int l=rvt[v][i].l; if(!find[y]&&d[y]>d[v]+l) { d[y]=d[v]+l; tt.v=y; tt.w=d[y]; q.push(tt); } } } } int Astar() { memset(cnt,0,sizeof(cnt)); aastar ss,tt; ss.v=s,ss.w=0; if(d[s]==inf)return -1; if(s==t)k++; priority_queue<aastar>q; q.push(ss); while(!q.empty()) { ss=q.top(); q.pop(); int v=ss.v; int w=ss.w; if(v==t) { cnt[t]++; if(cnt[t]==k) return w; } else cnt[v]++; if(cnt[v]>k)continue; for(int i=0;i<vt[v].size();i++) { int y=vt[v][i].y; int l=vt[v][i].l; tt.v=y,tt.w=w+l; q.push(tt); } } return -1; } int main() { while(2==scanf("%d%d",&n,&m)) { int a,b,c; for(int i=1;i<=n;i++) { vt[i].clear(); rvt[i].clear(); } for(int i=0;i<m;i++) { scanf("%d%d%d",&a,&b,&c); node s; s.y=b,s.l=c; vt[a].push_back(s); s.y=a; rvt[b].push_back(s); } scanf("%d%d%d",&s,&t,&k); dijstra(); printf("%d\n",Astar()); } return 0; }