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