[SDOI2010]魔法猪学院
K短路,A*
新鲜出炉的A*
A是什么,其实就是bfs,只不过加了一个估价函数h(x),并把队列换成了优先队列。令h(x)==已经花费的代价,f(x)=g(x)+h(x),,那么f(x)就是优先队列的比较标准。这样我们就会尽可能向最优解的方向搜索,我们如果想要求最优解,就跑A,每次扩展状态,压入队列中,如果感觉要T了,直接结束程序,那么解极为可能就是最优解。
K短路有一个性质:估价函数是100%正确的,我们就利用优先队列扩展状态,如果我们到达了终点,就cnt++一次,直到cnt==k为止。这样我们就不会重复搜索。
但是,这种算法空间复杂度极高,IDA*正在学。
code:(92分)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cstring>
#include<vector>
#include<stack>
#define db double
using namespace std;
const int maxn=400006;
int head[maxn],cur,fhead[maxn];
struct hzw
{
int to,next;
db v;
}e[maxn],ed[maxn];
inline void add(int a,int b,db c,hzw e[],int head[])
{
e[cur].to=b;
e[cur].next=head[a];
e[cur].v=c;
head[a]=cur++;
}
typedef pair <double,int>p;
int n,m;
double dis[maxn];
double k;
inline void dij(int firs)
{
for (int i=1;i<=n;++i) dis[i]=1e17;
priority_queue<p,vector<p>,greater<p> >q;
q.push(p(0,firs));
dis[firs]=0;
while (!q.empty())
{
p fr=q.top();
q.pop();
int s=fr.second;
if (dis[s]<fr.first) continue;
for (int i=fhead[s];i!=-1;i=ed[i].next)
{
int v=ed[i].to;
double w=ed[i].v;
if (dis[v]>dis[s]+w)
{
dis[v]=dis[s]+w;
q.push(p(dis[v],v));
}
}
}
}
struct gk
{
db l,rnd;
int id;
bool operator <(const gk &rhs) const
{
return l+rnd>rhs.l+rhs.rnd;
}
};
inline int A_star(double lmt)
{
priority_queue<gk>q;
int cnt=0;
q.push((gk){0,dis[1],1});
while (!q.empty())
{
gk all=q.top();
q.pop();
int s=all.id;
db leth=all.l,fina=all.rnd;
if (s==n)
{
lmt-=leth;
if (lmt<=0) return cnt;
cnt++;
continue;
}
for (int i=head[s];i!=-1;i=e[i].next)
{
int v=e[i].to;
double w=e[i].v;
q.push((gk){leth+w,dis[v],v});
}
}
return cnt;
}
signed main()
{
memset(head,-1,sizeof(head));
memset(fhead,-1,sizeof(fhead));
cin>>n>>m>>k;
for (int i=1,a,b;i<=m;++i)
{
db c;
scanf("%d%d%lf",&a,&b,&c);
add(a,b,c,e,head);
add(b,a,c,ed,fhead);
}
dij(n);
cout<<A_star(k);
return 0;
}
总结:
A*算法适合解决寻找路径问题,她能尽可能的像最优解逼近。