像潮落潮涌,送我奔向自由。|

寂静的海底

园龄:3年2个月粉丝:59关注:15

A*算法正确性的证明

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

example

第k短路

题意

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


做法

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

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

考虑魔改dij ,首先发现st的最短路分成一些部分

u1u2u 性质 :p1 从中间任意选取u1,u2都不会用到k+1短路及i短路(i>k)

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

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

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

每个点只会被用于处理k次,该算法的时间复杂度是O(k×(nlogn+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:对于uv,h(u)h(v)

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

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

p1归纳得到。

p3(一句废话):对于同一个点,若h(x1)>h(x2)a(x1)>a(x2)

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

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

假设i+1k2转移来,ik1转移来。

即使h(k2)<h(k1),那么k2先被放入堆中,但是很明显有h(k1)h(i)h(i+1) 所以在i+1出堆前,k1会进堆并在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 @   寂静的海底  阅读(55)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起