【原创】KM算法的Bfs写法

KM算法的Bfs写法

引入–DfsKM的时间复杂度

我们已经学习了KM算法,现在我们来分析一下它的时间复杂度。

bool dfs(int s)
{
    visx[s]=1;
    for(int i=1;i<=cnty;i++) 
        if(!visy[i])
        {
            int t=wx[s]+wy[i]-dis[s][i];
            if(t==0)
            {
                visy[i]=1;
                if(linky[i]==0||dfs(linky[i]))
                {
                    linkx[s]=i,linky[i]=s;
                    return true;
                }
            }
            else if(t>0) 
                if(treturn false;
}

void km()
{
    memset(linkx,0,sizeof linkx); 
    memset(linky,0,sizeof linky);
    for(int i=1;i<=cntx;i++)
    {
        while(1)
        {
            minz=INF;
            memset(visx,0,sizeof visx);
            memset(visy,0,sizeof visy);
            if(dfs(i))break;
            for(int j=1;j<=cntx;j++)  //将交错树中X部的点的顶标减去minz
            if(visx[j])wx[j]-=minz;
            for(int j=1;j<=cnty;j++) //将交错树中Y部的点的顶标加上minz
            if(visy[j])wy[j]+=minz;
        }
    }
}

KM算法每修改一次顶标需要调用一次dfs找增广路径,如果采用邻接矩阵存储边权,则一次dfs的时间复杂度是O(N^2)。那么需要修改多少次顶标呢?我们知道修改一次顶标必然导致至少一条边加入相等子图。最多有n^2条边,所以最多会修改顶标n^2次。所以总的时间复杂度是O(N^4)

网上有人说,加一个slack数组记录最小差,可以降低时间复杂度—-确实是的,对于随机数据来说,时间复杂度约为O(n^3)。但是!!!
如果我们考虑极限数据,把每条边的边权dis[i][j]=i*j,试试看吧,会怎样?+-+

闪亮登场–BfsKM

void bfs(int k)
{
    int px,py=0,yy=0,d;
    memset(pre,0,sizeof pre);
    memset(slack,0x3f,sizeof slack);
    linky[py]=k;

    do
    {
        px=linky[py],d=0x3f3f3f3f,vis[py]=1;
        for(int i=1;i<=n;i++)
            if(vis[i]==0)
            {
                if(slack[i]>dbx[px]+dby[i]-C[px][i])
                    slack[i]=dbx[px]+dby[i]-C[px][i],pre[i]=py;
                if(slack[i]for(int i=0;i<=n;i++)
            if(vis[i]) dbx[linky[i]]-=d,dby[i]+=d;
            else slack[i]-=d;
        py=yy;
    }while(linky[py]!=0);
    while(py) linky[py]=linky[pre[py]],py=pre[py];
}
void km()
{
    memset(dbx,0,sizeof dbx);
    memset(dby,0,sizeof dby);
    memset(linky,0,sizeof linky);
    for(int i=1;i<=n;i++)
        memset(vis,0,sizeof vis),bfs(i);
}

需要注意的是,这里的slack[i]的值所记录的最小差值,并不一定是最后一次根据路径访问到此边时的最小差(即delta),
它很可能是之前的一次访问所产生的差值,这样的前一个点是保存在pre中的,相当于是同时在多条增广路中同时找边。
它的时间复杂度真正实现了O(n^3)

建议仔细理解含义,实在不行就背下来。

你可能感兴趣的:(#,心得)