打算开始做题了。在这样耗散下去实在是不好意思跟别人讲弄过ACM。
这是一道最基本的第k短路的题,很久没有做过A*的题几乎都忘了原理。还有就是这次写个dij都一直手贱。
思路:
1.A*:现在对于A*的理解是:f(x)=h(x)+g(x).其中h(x)是从起始点到当前节点的花费,g(x)是估价函数,估计的是当前节点x到目的节点的花费。这个估计值一定要比实际值小,对于A*的不同就是估价函数的选取不同,这道题用的是最短路(曾经我用过两点间直线最短,还有就是两点间的x距离和y距离之和),其实,我这次再看了一遍资料觉得这个很像BFS,BFS就是把访问过的放到优先队列,只是那里g(x)是为0,也就是找到当前代价最小的继续访问,而A*是找到当前f(x)最小的进行访问。
2.对于k短路来讲也就是在A*搜索的过程中,目的节点出队列的次数为第k次。第一次出队列肯定是最短路。
3.这题的坑:重边,起始点等于目的点(需要判断如果相等那么k++,因为A*会算0为最短路)
代码:
#include<cstdio>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;
int ed[1010][1010];
int h[1010],g[1010],dis[1010];
int inf=10000001;
struct node{
int v,w;
};
vector<node>edt[1010];
struct cnode{
int u;
int len;
cnode(int uu,int ww):u(uu),len(ww){}
friend bool operator < (cnode a,cnode b){
return a.len+dis[a.u]>b.len+dis[b.u];
}
};
void dij(int sta,int n){
int flag[1010];
for(int i=0;i<=1009;i++){
dis[i]=inf;
flag[i]=0;
}
dis[sta]=0;
int u=sta;
flag[u]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[u]+ed[u][j]<dis[j]){
dis[j]=dis[u]+ed[u][j];
}
}
int max=inf;
for(int j=1;j<=n;j++){
if(dis[j]<max && !flag[j]){
u=j;
max=dis[j];
}
}
if(u!=inf)
flag[u]=1;
}
}
int tot[1010];
int a_star(int s,int n,int k,int e){
if(dis[s]==inf) return -1;
priority_queue<cnode>que;
memset(tot,0,sizeof(tot));
que.push(cnode(s,0));
if(s==e)k++;
while(!que.empty()){
cnode cnt=que.top();
que.pop();
tot[cnt.u]++;
if(tot[cnt.u]==k && cnt.u==e) return cnt.len;
for(int i=0;i<edt[cnt.u].size();i++){
que.push(cnode(edt[cnt.u][i].v,cnt.len+edt[cnt.u][i].w));
}
}
return -1;
}
main(){
int n,m;
while(scanf("%d%d",&n,&m)!=-1){
int a,b,t,s,e,k;
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
ed[i][j]=inf;
}
edt[i].clear();
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&t);
if(t<ed[b][a])
ed[b][a]=t;
node nnode;
nnode.v=b;
nnode.w=t;
edt[a].push_back(nnode);
}
scanf("%d%d%d",&s,&e,&k);
dij(e,n);
printf("%d\n",a_star(s,n,k,e));
}
}