【HDU】2255奔小康赚大钱 二分图最大权匹配&KM算法

传送门:hdu2255


题解

KM算法模板题
推荐两篇博客:
KM算法 详解+模板-Chierush (理论讲解清晰,附带模板)
km算法入门-logosG (有算法的模拟和详细图解)


代码

#include
using namespace std;
const int N=330,inf=0x3f3f3f3f;

int n,tim,g[N][N],bel[N];
int slack[N],vis[2][N],tg[2][N];

bool dfs(int x)
{
    int i,j;vis[0][x]=tim;
    for(int i=1;i<=n;++i) if(vis[1][i]!=tim){
        j=tg[0][x]+tg[1][i]-g[x][i];
        if(!j){
            vis[1][i]=tim;//选用后再标记vis
            if(!bel[i] || dfs(bel[i])){
                bel[i]=x;return true;
            }
        }else slack[i]=min(slack[i],j);//更新slack,保证最小
    }
    return false;
}

inline int KM()
{
    int x,i,j,d,re=0;tim=0;
    memset(tg,0,sizeof(tg));
    memset(bel,0,sizeof(bel));
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;++i)
     for(j=1;j<=n;++j)
      tg[0][i]=max(tg[0][i],g[i][j]);//初始化点集S的标号
    for(x=1;x<=n;++x){
        memset(slack,0x3f,sizeof(slack));//初始化为inf
        for(;;){
            tim++;
            if(dfs(x)) break;
            d=inf;
            for(i=1;i<=n;++i) if(vis[1][i]!=tim)
              d=min(d,slack[i]);
            for(i=1;i<=n;++i) if(vis[0][i]==tim)
                tg[0][i]-=d;
            for(i=1;i<=n;++i)
             if(vis[1][i]==tim) tg[1][i]+=d;
             else slack[i]-=d;
            //以上为增广操作,注意slack[i]=tg[1][i]+tg[0][x(x属于S)]-w[x][i],tg[0][x]减小的同时slack[i]也要减小
        }
    }
    for(i=1;i<=n;++i) if(bel[i])
        re+=g[bel[i]][i];
    return re;
}

int main(){
    int i,j;
    while(scanf("%d",&n)==1){
        for(i=1;i<=n;++i)
         for(j=1;j<=n;++j)
          scanf("%d",&g[i][j]);
        printf("%d\n",KM());
    }
}

你可能感兴趣的:(二分图匹配)