HDOJ 2255 奔小康赚大钱 (二分图最优匹配-KM算法)

模型:给一个完全二部图,每条边都有一个权值,求边权和最大的匹配。

数据范围:n<=250

分析:直接套用KM算法即可,要加slack数组优化,优化后复杂度为O(N3)。

View Code
#include <stdio.h>

#include <string.h>

#define N 300

#define INF 0x7fffffff

#define MIN(a,b) ((a)<(b)?(a):(b))

#define MAX(a,b) ((a)>(b)?(a):(b))



int n,g[N][N];

int x[N],y[N],lx[N],ly[N],match[N],slack[N];



void init()

{

    for(int i=0;i<n;i++)

    {

        lx[i]=ly[i]=0;

        for(int j=0;j<n;j++)

        {

            scanf("%d",&g[i][j]);

            lx[i]=MAX(lx[i],g[i][j]);

        }

    }

}

int path(int u)

{

    x[u]=1;

    for(int v=0;v<n;v++)    if(!y[v])

    {

        int t=lx[u]+ly[v]-g[u][v];

        if(t>0)

        {

            slack[v]=MIN(slack[v],t);

            continue;

        }

        y[v]=1;

        if(match[v]==-1 || path(match[v]))

        {

            match[v]=u;

            return 1;

        }

    }

    return 0;

}

void KM()

{

    memset(match,-1,sizeof(match));



    for(int u=0;u<n;u++)

    {

        for(int v=0;v<n;v++)    slack[v]=INF;

        while(1)

        {

            memset(x,0,sizeof(x));

            memset(y,0,sizeof(y));

            if(path(u)) break;



            int d=INF;

            for(int j=0;j<n;j++)    if(!y[j])

            {

                d=MIN(d,slack[j]);

            }

            for(int i=0;i<n;i++)    if(x[i])

            {

                lx[i]-=d;

            }

            for(int j=0;j<n;j++)

            {

                if(y[j])    ly[j]+=d;

                else    slack[j]-=d;

            }

        }

    }

    int ans=0;

    for(int j=0;j<n;j++)    ans+=g[match[j]][j];

    printf("%d\n",ans);

}

int main()

{

    while(~scanf("%d",&n))

    {

        init();

        KM();

    }

    return 0;

}

 

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