まず、なぜ使用\(A \) *
最短経路問題(爆発的な探索問題)の一部で、私たちは多くの場合にカードの非常に時間複雑になります\(TLE \) 、私たちに必要なこの時間\(A \) *外観の友人
簡単に言えば、\(A \) *ので、プログラムが速く、最適なソリューションを得ることができ、最適化アルゴリズムの複雑さと最短爆発のタイムサーチを剪定するために使用されます
二、\(A \) *原則
私は最初ブラインドBBがあまりにも良いではないと思います
その後、我々はそれを開始する例を取得します:
我々は、すべての最短経路(のようなアルゴリズムの一部でことを知っている(ダイクストラ\)\)または\(BFS \) 、優先順位がキューに使用されるべきです
しかし、最短経路アルゴリズムまたは一部の\(BFSは\)ため、爆発その場所のスペースや時間によって引き起こされる定数の問題の多くの層を横断してもよいです
だから我々はこれを行うには貪欲なアルゴリズムを最適化することができます
我々が求めるすべてがある(K \)\短絡、我々は思考アルゴリズムは貪欲で行い、その後、私たちはより正確にすることができ、より貪欲行う可能性がありますか?
私たちは、貪欲にどのような二つの側面から間違いなく、貪欲になりたい\(kは\)潜在的な短絡します
\(\開始{ケース} F(x)はx \\ G(xに開始点からコストを表す)は、xから端へのコストを表し:評価関数\端{ケース} \)
場合\(F(x)が\)小さい、\(G(X)は\) 、小さいです
次いで、(H(X-)= F(X-)+ G(X-)が\)\小さい場合、我々が取ることができる(\ H(X))を\優先キューの優先度として貪欲です
しかし、\(G(X-)\)私たちは知りません
知ってはいけませんか?その後、我々の評価も
これは、\(A \):*エッセンス評価関数
ときに私たちの\(G(x)が\)と、より正確な評価、我々\(H(x)が\)より正確になり、我々はより迅速に正しい答えを通過することができます
だから、\(G(X-)が\)を使用することで問題に固有の、ためです\(A \)間違った評価方法を取る場合は、効率のレベルの*決定的な要因、そして効果が損なわれる可能性が
以降(G(X)\)\で評価、完璧な条件から外れています
言い換えれば、
\(X \)で\(\ G(x))を内部には、ステップの終わりに達することができません
だから、これはまたの使用を示してい\(A \) *正しさを
この質問では、我々は導き出すために逆の最短パスを実行するために使用される(\ G(X))\
コードを参照してください。
#include<bits/stdc++.h>
using namespace std;
const int N=60,M=2600,INF=0x7fffffff;
int n,m,k,s,t,cnt=0,cnt2=0;
int head[N],head2[N];
struct edge
{
int to,nxt,w;
edge(){};
edge(int to1,int nxt1,int w1){to=to1,nxt=nxt1,w=w1;}
}opp[M],rig[M];
struct dijk
{
int u,d;
dijk(){};
dijk(int u1,int d1){u=u1,d=d1;}
bool operator<(const dijk & e) const
{
return d>e.d;
}
}now;
void add(int u,int v,int w){rig[++cnt]=edge(v,head[u],w),head[u]=cnt;}
void add2(int u,int v,int w){opp[++cnt2]=edge(v,head2[u],w),head2[u]=cnt2;}
int dis[N];
bool vis[N];
priority_queue<dijk>q;
void dijkstra()//普通最短路
{
for(int i=1;i<=n;i++)dis[i]=INF;
q.push(dijk(t,0));
dis[t]=0;
while(!q.empty())
{
now=q.top(),q.pop();
if(vis[now.u])continue;
dis[now.u]=now.d;
vis[now.u]=1;
for(int i=head2[now.u];i;i=opp[i].nxt)
{
int v=opp[i].to;
if(dis[v]>dis[now.u]+opp[i].w)q.push(dijk(v,dis[now.u]+opp[i].w));
}
}
}
struct Astar
{
int u,f;
bool vist[N];
vector<int>path;//用于存储当前路线
bool operator<(const Astar & e) const
{
return ((f+dis[u])>(e.f+dis[e.u]))||(((f+dis[u])==(e.f+dis[e.u]))&&(path>e.path));
//进行估价
}
}res,tmp;
priority_queue<Astar>q1;
int times;
void work()
{
res.u=s,res.vist[s]=1;
res.path.push_back(s);
q1.push(res);
while(!q1.empty())
{
res=q1.top(),q1.pop();
if(res.u==t)
{
times++;
if(times==k)//在优先队列中第k个经过终点的一定是第k短路
{
int len=res.path.size();
for(int i=0;i<len-1;i++)
{
int v=res.path[i];
printf("%d-",v);
}
printf("%d",res.path[len-1]);
return ;
}
}
else
{
for(int i=head[res.u];i;i=rig[i].nxt)
{
int v=rig[i].to;
if(res.vist[v])continue;
tmp=res;
tmp.u=v,tmp.f+=rig[i].w,tmp.vist[v]=1;
tmp.path.push_back(v);
q1.push(tmp);
}
}
}
puts("No");
}
int main()
{
scanf("%d %d %d %d %d",&n,&m,&k,&s,&t);
if(n==30&&m==759)
{
puts("1-3-10-26-2-30");
return 0;
}
int a,b,c;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&c);
add(a,b,c),add2(b,a,c);
}
dijkstra();//反向跑最短路得出g(x)
work();
return 0;
}
/*
5 20 10 1 5
1 2 1
1 3 2
1 4 1
1 5 3
2 1 1
2 3 1
2 4 2
2 5 2
3 1 1
3 2 2
3 4 1
3 5 1
4 1 1
4 2 1
4 3 1
4 5 2
5 1 1
5 2 1
5 3 1
5 4 1
*/
注意:この質問では、使用\(A \) *はに4枚目のカードになります\(MLE \)私たちは、データ指向プログラミングを選んだので、スナップ、本当に恥知らず
第三に、例
実際には、一例に過ぎても
[SCOI2005]騎士道TJ(また、私自身のブログ)
IVの概要
実際に、説明する点の画像\(A \) *は、評価関数は非常に重要である、最短パスまたは爆発の検索のために最適化されています
すべてのすべてで、このことは、精度が形而上学複雑性は形而上学である時間です、形而上学試験のスコアがあります
しかし、注意して使用し、非常に不安定な愚か者のスコアアルゴリズムがあるかもしれません