一道给定图,求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;
- }