K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院
2018-05-15 20:34
330 查看
A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数
这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离
通常和Dijkstra一起解决K短路
BZOJ1598:牛跑步
求前K短路
因为A*算法我们每次用来向外拓展的是估价函数最小的点,那么,我们必定能够得到,第一个到达n的是最短路。(Dijkstra的贪心,可证)
那么,我们思考一下,第二个到达n的就是次短路!
由此观之:第K个到达的就是K短路
因此,A*算法可以用来解决K短路问题
附上代码:
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <cstdlib> #include <queue> #include <iostream> #include <map> using namespace std; #define N 10005 #define ll long long struct node { int to,next,val; }e[N*10],E[N*10]; int head ,cnt,cnt1,n,m,K,vis ,head1 ; int dis ; void add(int x,int y,int z) { e[cnt].to=y; e[cnt].next=head[x]; e[cnt].val=z; head[x]=cnt++; } void add1(int x,int y,int z) { E[cnt1].to=y; E[cnt1].next=head1[x]; E[cnt1].val=z; head1[x]=cnt1++; } priority_queue<pair<int ,int > >q; void Dijkstra() { memset(dis,0x3f,sizeof(dis)); dis =0; q.push(make_pair(0,n)); while(!q.empty()) { int x=q.top().second;q.pop(); if(vis[x])continue; vis[x]=1; for(int i=head1[x];i!=-1;i=E[i].next) { int to1=E[i].to; if(dis[to1]>dis[x]+E[i].val) { dis[to1]=dis[x]+E[i].val; q.push(make_pair(-dis[to1],to1)); } } } } void Astar(int s) { q.push(make_pair(-dis[s],s)); while(!q.empty()) { int d=q.top().first;int x=q.top().second;q.pop(); if(x==n) { K--; printf("%d\n",-d); if(!K)return ; } for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; q.push(make_pair(d+dis[x]-e[i].val-dis[to1],to1)); } } } int main() { memset(head1,-1,sizeof(head1)); memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&m,&K); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(y,x,z); add1(x,y,z); } Dijkstra(); Astar(1); while(K--)puts("-1"); return 0; }
1975: [Sdoi2010]魔法猪学院
这个贪心贪的很显然,为了尽可能的多,自然是选择前K短路
那么,同样,我们用Dijkstra的贪心方法求n的前K短路
但是这种方法实际的时间复杂度不是很对,理论上可以过很多题。这道题BZOJ可以过,但是洛谷上过不去
附上不完美的代码:
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <cstdlib> #include <queue> #include <iostream> #include <map> using namespace std; #define N 5005 #define ll long long struct node { int to,next; double val; }e[200005],E[200005]; int head ,cnt,cnt1,n,m,vis ,head1 ,ans; double dis ,K; void add(int x,int y,double z) { e[cnt].to=y; e[cnt].next=head[x]; e[cnt].val=z; head[x]=cnt++; } void add1(int x,int y,double z) { E[cnt1].to=y; E[cnt1].next=head1[x]; E[cnt1].val=z; head1[x]=cnt1++; } priority_queue<pair<double ,int > >q; void Dijkstra() { for(int i=0;i<N;i++)dis[i]=1e9; dis =0; q.push(make_pair(0,n)); while(!q.empty()) { int x=q.top().second;q.pop(); if(vis[x])continue; vis[x]=1; for(int i=head1[x];i!=-1;i=E[i].next) { int to1=E[i].to; if(dis[to1]>dis[x]+E[i].val) { dis[to1]=dis[x]+E[i].val; q.push(make_pair(-dis[to1],to1)); } } } } void Astar(int s) { q.push(make_pair(-dis[s],s)); while(!q.empty()) { double d=q.top().first;int x=q.top().second;q.pop(); if(x==n) { if(K+d<0-1e-9)return ; K+=d; ans++; } for(int i=head[x];i!=-1;i=e[i].next) { int to1=e[i].to; q.push(make_pair(d+dis[x]-e[i].val-dis[to1],to1)); } } } int main() { memset(head1,-1,sizeof(head1)); memset(head,-1,sizeof(head)); scanf("%d%d%lf",&n,&m,&K); for(int i=1;i<=m;i++) { int x,y;double z; scanf("%d%d%lf",&x,&y,&z); add(x,y,z); add1(y,x,z); } Dijkstra(); Astar(1); printf("%d\n",ans); return 0; }
正解是用可持久化可并堆+A*算法,挖坑待填
相关文章推荐
- bzoj1598[Usaco2008 Mar]牛跑步 K短路模板 spfa+dij
- [bzoj1598][Usaco2008 Mar]牛跑步 dijkstra k短路
- [BZOJ1598][Usaco2008 Mar]牛跑步(k短路)
- bzoj 1598: [Usaco2008 Mar]牛跑步 [k短路 A*] [学习笔记]
- bzoj 1598: [Usaco2008 Mar]牛跑步【A*K短路】
- 【k短路】【bzoj 1598】: [Usaco2008 Mar]牛跑步
- 【BZOJ】1598 [Usaco2008 Mar]牛跑步 k短路(最短路径+A*)
- BZOJ 1598: [Usaco2008 Mar]牛跑步 A* K短路
- bzoj 1598: [Usaco2008 Mar]牛跑步 (k短路)
- bzoj 1598: [Usaco2008 Mar]牛跑步 -- 第k短路,A*
- Bzoj 1598: [Usaco2008 Mar]牛跑步 dijkstra,堆,K短路,A*
- BZOJ 1975: [Sdoi2010]魔法猪学院【K短路,A*
- BZOJ1598: [Usaco2008 Mar]牛跑步
- 【bzoj1617】【Usaco2008 Mar】River Crossing (dp)题解&代码
- [SDOI2010]魔法猪学院 --k短路
- BZOJ 1975: [Sdoi2010]魔法猪学院——K短路,A*
- BZOJ 1975 [Sdoi2010]魔法猪学院 - k短路(手写堆)
- [BZOJ1975][SDOI2010]魔法猪学院(k短路,A*)
- [bzoj1598][Usaco2008 Mar]牛跑步
- [SDOI2010]魔法猪学院(Astar 优化K短路)