【k短路&A*算法】BZOJ1975: [Sdoi2010]魔法猪学院

时间:2021-08-03 19:59:24

Description

找出1~k短路的长度。
 

Solution

k短路的求解要用到A*算法

A*算法的启发式函数f(n)=g(n)+h(n)

g(n)是状态空间中搜索到n所花的实际代价

h(n)是n到结束状态最佳路径的估计代价

关于h(n)的选取,当h(n)<实际代价时,搜索慢但可出解;h(n)=实际代价时,正确率与效率最高;h(n)>实际代价,快但只能得到近似解。

但在k短路问题中,h(n)是可以选到准确值的,就是n到结束节点的最短路,预处理时从结束节点做一次单源最短路即可。

按广搜的方式扩展节点,每次优先扩展f(n)最小的节点。

第i次扩展到目标节点,代表找到了第i短路。

正确性什么的很好理解。

k短路关于A*部分代码很简洁,用优先队列维护。

 

这道题就是裸题,但这道题很丧病地让proirity_queueMLE,于是要手写堆。

让我这个几乎没手写过堆的STL狗QwQ

 

Code

  1 #include<cstdio>
2 #include<algorithm>
3 #include<queue>
4 #include<cstring>
5 using namespace std;
6 const int N=5e3+5,M=2e5+5;
7
8 double d[N];
9 int head[N],e[M],nxt[M],cnt;
10 double w[M];
11 int adde(int u,int v,double g){
12 e[++cnt]=v;w[cnt]=g;nxt[cnt]=head[u];head[u]=cnt;
13 }
14 int _head[N],_e[M],_nxt[M],_cnt;
15 double _w[M];
16 int _adde(int u,int v,double g){
17 _e[++_cnt]=v;_w[_cnt]=g;_nxt[_cnt]=_head[u];_head[u]=_cnt;
18 }
19 struct node{
20 double f,g;
21 int o;
22 bool operator<(const node&a)
23 const{return f<a.f;}
24 };
25 int n,m;
26 double c;
27
28 queue<int>q;
29 int inque[N];
30 int spfa(){
31 memset(d,127,sizeof(d));
32 d[n]=0;
33 inque[n]=1;
34 q.push(n);
35
36 while(!q.empty()){
37 int u=q.front();q.pop();
38 for(int i=_head[u];i;i=_nxt[i]){
39 int v=_e[i];
40 if(d[v]>d[u]+_w[i]){
41 d[v]=d[u]+_w[i];
42 if(!inque[v]){
43 q.push(v);
44 inque[v]=1;
45 }
46 }
47 }
48 inque[u]=0;
49 }
50 }
51
52 int ans,size;
53 node Q[2000000];
54 int push(node x){
55 int now,next;
56 Q[++size]=x;
57 now=size;
58 while(now>1){
59 next=now>>1;
60 if(Q[next]<Q[now]) break;
61 swap(Q[now],Q[next]);
62 now=next;
63 }
64 }
65 node pop(){
66 int now,next;
67 node ret;
68 ret=Q[1];
69 Q[1]=Q[size--];
70 now=1;
71 while((now<<1)<=size){
72 next=now<<1;
73 if(next<size&&Q[next+1]<Q[next]) next++;
74 if(Q[now]<Q[next]) break;
75 swap(Q[now],Q[next]);
76 now=next;
77 }
78 return ret;
79 }
80 void Astar(){
81 push((node){d[1],0,1});
82 while(size){
83 node x=pop();
84 for(int i=head[x.o];i;i=nxt[i]){
85 int v=e[i];
86 push((node){x.g+w[i]+d[v],x.g+w[i],v});
87 }
88 if(x.o==n){
89 c-=x.f;
90 if(c<0) return;
91 ans++;
92 }
93 }
94 }
95
96 int main(){
97 scanf("%d%d%lf",&n,&m,&c);
98 int u,v; double g;
99 for(int i=1;i<=m;i++){
100 scanf("%d%d%lf",&u,&v,&g);
101 adde(u,v,g);
102 _adde(v,u,g);
103 }
104
105 spfa();
106 Astar();
107
108 printf("%d\n",ans);
109 return 0;
110 }