A*算法正确性的证明

我们首先讨论在具体实际情况下正确性的讨论

example

第k短路

题意

求有向正边权简单图$G$中点$s$到点$t$的 非严格第k短路 。


做法

首先考虑朴素的dij 的原理。

由于dij每次取出的是目前的$dis$最小的点,它不会被别的点更新,所以着一定就是起点到$u$的最短路。

考虑魔改$dij$ ,首先发现$s$到$t$的最短路分成一些部分

$$ u_1\to u_2\to\dots \to u $$ 性质 :$p1$ 从中间任意选取$u1$,$u2$都不会用到k+1短路及i短路$(i>k)$。

因为用k短路一定更短,用数学归纳法可以简单地证明。

所以我们只用处理前k短路,然后堆优化的dij每次弹出的恰好是里面目前最短的,也就是说每个点第i次被弹出,此时的dis就是第i小值。

然后可以发现每个点被弹出k次后就不用再用于更新其他点了。(性质$p1$)

每个点只会被用于处理k次,该算法的时间复杂度是$O(k \times( n \log n + m) )$

接下来考虑使用A*算法,即使用估价函数来优化bfs顺序。

由于A*的性质,所以估价函数$f(x)$应小于等于实际从起点走到终点的k短路在x到终点的部分。

所以我们选取估价函数$f(x)$表示x到终点的距离。

将dij中堆的优先级设为$\{h(x)=g(x)+f(x)\}_{min}$即可,其中$g(x)$表示从起点到目前状况的代价即可。

同样,每个点被弹出k次后就不用再用于更新其他点了。


正确性证明:

令$a(x)$表示实际总代价

$h(x)$表示总估价,

$g(x)$表示目前代价,

$f(x)$表示未来估价。

性质

$p1$:对于$u \to v , h(u)\leq h(v)$

文字理解:这一步做了最优决策,那么$h(u)$才能等于$h(v)$,其他选择都不优于最优选择,故$ h(u)\leq h(v)$

$p2$:对于拓扑序(不是拓扑序列) $h(x)$单调不减

由$p1$归纳得到。

$p3$(一句废话):对于同一个点,若$h(x_1)>h(x_2)$则$a(x_1)>a(x_2)$

即若按照堆的优先级来取,若第$i$短和第$i+1$短的都在堆里,那么每次取出一定是第$i$大。

由$p3$我们只需要证明当第i+1短的出堆时,i短的已经处理过了。

假设$i+1$由$k_2$转移来,$i$由$k_1$转移来。

即使$h(k_2)<h(k_1)$,那么$k_2$先被放入堆中,但是很明显有$h(k_1)\leq h(i) \leq h(i+1)$ 所以在$i+1$出堆前,$k_1$会进堆并在$i+1$出堆前扩展出$i$

使数学归纳法可推广至任意情况。

又因为$p3$同一个点的出堆顺序一定是正确的。

所以第$i$次取出的是第$i$小值

证毕

code :

#include<bits/stdc++.h>
using namespace std;

#define pb push_back
#define mp make_pair
#define min3(xxx,yyy,zzz) min(min(xxx,yyy),zzz)
#define max3(xxx,yyy,zzz) max(max(xxx,yyy),zzz)
#define pii pair<int,int>
#define fi first
#define se second
#define rep(variable,leftrange,rightrange) for(int variable=leftrange;variable<=rightrange;++variable)
#define Rep(variable,leftrange,rightrange) for(int variable=leftrange;variable>=rightrange;--variable)
#define lb long double
#define mem(x,y) memset(x,y,sizeof x) 
#define sq(x) ((x)*(x))
#define ss stable_sort
#define rs random_shuffle
#define nxp next_permutation
#define lowbit(x) (x& -x)
#define ll long long
#define lll __int128
#define gi greater<int>
#define vi vector<int>
#define upmin(x,y) x=min(x,y)
#define upmax(x,y) x=max(x,y)

template <typename T>inline void read(T &t)
{int c=getchar();t=0;while(!isdigit(c))c=getchar();while(isdigit(c))t=(t<<3)+(t<<1)+c-48,c=getchar();}
template <typename T,typename... Args> inline void read(T& t, Args&... args){read(t);read(args...);}
template <typename T> inline void wrt(T x)
{if(0<=x&&x<10) {putchar(x+'0');return ;}wrt(x/10);putchar(x%10+'0');}
template <typename T> inline void wrt(T x,char c) {wrt(x);putchar(c);}

const int N= 1004 ;

const int M= 100004;

struct edge{
    int v,w;
} ;

vector<edge> ed[N],fed[N];
void adde(int u,int v,int w)
{
ed[u].push_back((edge){v,w});
} 

void fadde(int u,int v,int w)
{
fed[u].push_back((edge){v,w});
}
int n,m,fdis[N],vis[N],dis[N],cnt[N];
int s,t,k;

priority_queue<pii >  q;

void dij()
{
    memset(fdis,0x3f,sizeof fdis);
    q.push({0,t});
    fdis[t]=0;
    while(!q.empty())
    {
        auto np = q.top();
        int po = np.second;
//        int ndis = -np.fi;
        q.pop();
        if(vis[po]) continue ;
        vis[po]=1;
        for(int i=0;i<fed[po].size();++i)
        {
            int v = fed[po][i].v;
            int w = fed[po][i].w;
            if(fdis[v]>fdis[po]+w) 
            {
                fdis[v]=fdis[po]+w;
                q.push({-(fdis[po]+w),v});
            }
        }
    }
}
struct point{
    int p,g,f;
    bool operator<(const point &p1) const {
        return f>p1.f;
    }
};
priority_queue<point> aq;
int A()
{
    aq.push((point){s,0,fdis[s]});
    while(!aq.empty())
    {
        point np = aq.top();
        aq.pop();
        int pos=np.p;
        cnt[pos]++;
        if(cnt[t]>=k) return np.g;
        for(int i=0;i<ed[pos].size();++i)
        {
            int tp  = ed[pos][i] . v;
            if(cnt[tp]<k) 
            aq.push((point){tp,np.g+ed[pos][i].w,np.g+ed[pos][i].w+fdis[tp]});
        }
    }
    return -1;
}
int main()
{
    read(n,m);
    rep(i,1,m)
    {
        int u,v,w;
        read(u,v,w);
        adde(u,v,w);
        fadde(v,u,w);
    }
    read(s,t,k);
    if(s==t)k++;
    dij();
    int ans = A();
    cout<<ans;
    return  0;
}
posted @ 2021-12-22 10:56  寂静的海底  阅读(137)  评论(0)    收藏  举报  来源