【原创】KM算法的Bfs写法

来源:互联网 发布:螺旋打印二维数组 编辑:程序博客网 时间:2024/05/22 02:45

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(t<minz)minz=t;        }    return 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]<d) d=slack[i],yy=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)

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

原创粉丝点击