题记
这题真的改死我(再见
哦还被diss了好久(再见
嗯感觉还有坑!(再见
题意
poj2449
有n条边,求s到t的第k短路
题解
这这这就A*算法模板吧【捂脸】
A*是啥呢
有人说是启发式合并吧…
我们定义一个评估值f(x)=g(x)+h(x)(例如求k短路中g(x)表示已经走了多远,h(x)表示从这个点到终点的最短路)f(x)越小就意味着越好咯,我们每次都去寻找最小的f(x)来进行操作,那不就很妙了
那k短路怎么求呢
我们就先求出每个点到终点的最短路——把图反过来..从t做最短路【捂脸】 这样就求出来了h(x)
然后就..每次做一个点,然后…求一个f(x),扔进优先队列里..
最后t出现k次也就可以了
嗯这里..我被鄙视了…我..开始认为..可以随便选一个点,如果这个点出现k次就直接返回它的g(x)+h(x)..然而有可能出现后面比它短..
哦对这题..假如s==t,这题认为..不能直接到…所以它的第一短路也要走一圈【捂脸】
代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define N 1100
#define M 100010
#define inf 1000000000
int num1=0,num2=0,n,m,s,t,k,h1[N],h2[N],d[N],flag[N];
struct node1{int x,y,z,next;}mp1[M],mp2[M];
struct node{
int v,c;
node(int vv,int cc) : v(vv),c(cc){}
friend bool operator < (node x,node y){return x.c+d[x.v]>y.c+d[y.v];}
};
void insert1(int x,int y,int z){mp1[++num1].x=x;mp1[num1].y=y;mp1[num1].z=z;mp1[num1].next=h1[x];h1[x]=num1;}
void insert2(int x,int y,int z){mp2[++num2].x=x;mp2[num2].y=y;mp2[num2].z=z;mp2[num2].next=h2[x];h2[x]=num2;}
void spfa(){
queue<int>Q;Q.push(t);
for(int i=1;i<=n;i++) d[i]=inf;d[t]=0;
memset(flag,0,sizeof(flag));flag[t]=1;
while(!Q.empty()){
int u=Q.front();Q.pop();flag[u]=0;
for(int i=h1[u];i;i=mp1[i].next){
int v=mp1[i].y;
if(d[v]>d[u]+mp1[i].z){
d[v]=d[u]+mp1[i].z;
if(!flag[v]){
flag[v]=1;
Q.push(v);
}
}
}
}
}
int astar(){
if(d[s]==inf) return -1;
priority_queue<node>p;
int cnt=0;p.push(node(s,0));
while(!p.empty()){
node u=p.top();p.pop();
if(u.v==t){
cnt++;
if(cnt==k) return u.c;
}
for(int i=h2[u.v];i;i=mp2[i].next){
int y=mp2[i].y;
p.push(node(y,u.c+mp2[i].z));
}
}return -1;
}
int main(){
while(scanf("%d%d",&n,&m)>0){
memset(h1,0,sizeof(h1));num1=0;
memset(h2,0,sizeof(h2));num2=0;
for(int i=1;i<=m;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
insert1(y,x,z);insert2(x,y,z);
}scanf("%d%d%d",&s,&t,&k);
spfa();
printf("%d\n",astar());
}
return 0;
}