题目大意
给定n个点m条边起点st终点ed求k短路(有向边)
分析
见到老伙计写了,于是乎就也来凑热闹般的写了第一道A*
一开始到是很蒙蔽的,但是经过刻(tou)苦(lan)的学习后,大概学习了一些。
就是把搜索优化减枝了,
设一个F函数来决定下一步的策略
在移动问题中F = G + H
其中:
G = 从起点s,沿着产生的路径,移动到网格上指定方格的移动耗费。
H = 从网格上那个方格移动到终点t的预估移动耗费。这经常被称为启发式的,这样叫的原因是因为它只是个猜测(不一定准确)。
当然,这道题中可以用spfa(dij+对优化poj会爆)求出H来(反向连边,从t开始跑)
然后每次从堆顶取点(这个点的F之最小)然后更新相邻的点,当第k次更新终点t时就找到了k短路。
各种奇怪的RE、TLE、MLE、WA······
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
struct arr{
int x,y,w,next;
}edge[200010];
int q[200010];
int ls[2010];
int lsr[2010];
int dis[2010];
int v[2010];
int n,m,s,t,k;
int edge_m;
struct cmp1{
long long x,f,g;
bool operator <(cmp1 b) const{
return b.f<f||b.f==f&&b.g<g;
}
};
void add(int x,int y,int w)
{
edge_m++;
edge[edge_m]=(arr){x,y,w,ls[x]};ls[x]=edge_m;
edge_m++;
edge[edge_m]=(arr){y,x,w,lsr[y]};lsr[y]=edge_m;
}
void spfa(int s)
{
for (int i=0;i<=n;i++) dis[i]=2000000000;
int head,tail;
head=0; tail=1;
dis[s]=0;
q[1]=s;
v[s]=1;
while (head<tail)
{
head++;
int x=q[head];
for (int i=lsr[x];i;i=edge[i].next)
if (dis[edge[i].y]>dis[x]+edge[i].w)
{
dis[edge[i].y]=dis[x]+edge[i].w;
if (!v[edge[i].y])
{
v[edge[i].y]=1;
tail++;
q[tail]=edge[i].y;
}
}
v[x]=0;
}
}
void A()
{
priority_queue<cmp1> gg;
gg.push((cmp1){s,dis[s],0});
int num=0;
while (gg.size())
{
cmp1 now;
now=gg.top();
gg.pop();
int x=now.x;
if (x==t)
{
num++;
if (num==k)
{
printf("%d\n",now.g);
return;
}
}
for (int j=ls[x];j;j=edge[j].next)
gg.push((cmp1){edge[j].y,now.g+edge[j].w+dis[edge[j].y],now.g+edge[j].w});
}
printf("-1\n");
return;
}
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
edge_m=0;
memset(edge,0,sizeof(edge));
memset(ls,0,sizeof(ls));
memset(lsr,0,sizeof(lsr));
for (int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
}
scanf("%d%d%d",&s,&t,&k);
spfa(t);
if (dis[s]==dis[0])
{
printf("-1\n");
continue;
}
if (s==t)
k++;
A();
}
return 0;
}