hdu 2853

虚拟赛一开始lyf就对我说这是一道匹配的题目,我一看明显裸的最优匹配,敲完提交wrong,

题目要求改变尽量少的公司,就是如果遇到相等的权值,优先选择跟他原来匹配的,KM匹配是按序号大小来的,如果一个公司原来匹配的序号较大,前面有权值相等的点时,KM就会选择前面的点参加匹配。想了好长时间不知道怎么去优先选择原来匹配的边,

最后想着如果把原来匹配的边变得大一些的话,就可以,但是变大的话就会影响最优匹配的总值,而且变大的话还会影响原来比他大的权值,所以就是所有的权值都得扩大,我想到的是都*100,原来匹配的边再加1,因为最多选50条边,也就是最多有50个01相加,不会超过一百,得到的答案除以一百,就把加的1都去掉了,只要扩大的倍数大于n就可以,,




 

#include<stdio.h>

#include<string.h>

#define N 55

#define inf 0x3fffffff

int map[N][N],lx[N],ly[N],sx[N],sy[N],d[N],n,m,match[N],Kmatch[N],tch[N];

int find(int x)

{

    sx[x]=1;

    for(int i=1;i<=m;i++)

    {

        if(sy[i]==1)continue;

        int temp=lx[x]+ly[i]-map[x][i];

        if(temp==0)

        {

            sy[i]=1;

            if(match[i]==-1||find(match[i])==1)

            {

                match[i]=x;

                Kmatch[x]=i;

                return 1;

            }

        }

        else d[i]=d[i]>temp?temp:d[i];

    }

    return 0;

}

int KM()

{

    int i,j,k,min,sum;

    memset(ly,0,sizeof(ly));

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

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

    for(i=1;i<=n;i++)

    {

        lx[i]=map[i][1];

        for(j=2;j<=m;j++)

            if(lx[i]<map[i][j])

                lx[i]=map[i][j];

    }

    for(i=1;i<=n;i++)

    {

        for(j=1;j<=m;j++)

            d[j]=inf;

        while(1)

        {

            memset(sx,0,sizeof(sx));

            memset(sy,0,sizeof(sy));

            if(find(i)==1)break;

            min=inf;

            for(k=1;k<=m;k++)

                if(sy[k]==0&&min>d[k])

                    min=d[k];

            for(j=1;j<=n;j++)

                if(sx[j]==1)lx[j]-=min;

            for(j=1;j<=m;j++)

                if(sy[j]==1)ly[j]+=min;

        }

    }

    sum=0;

    for(i=1;i<=n;i++)

        sum+=map[i][Kmatch[i]];

    return sum;

}

int main()

{

    int i,j,k,ans,sum;

    while(scanf("%d%d",&n,&m)!=-1)

    {

        for(i=1;i<=n;i++)

            for(j=1;j<=m;j++)

                map[i][j]=-inf;

        for(i=1;i<=n;i++)

            for(j=1;j<=m;j++)

            {

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

                map[i][j]*=100;

            }

        ans=0;

        for(i=1;i<=n;i++)

        {

            scanf("%d",&k);

            tch[i]=k;

            ans+=map[i][k];

            map[i][k]++;

        }

        ans/=100;

        sum=KM()/100;

        k=0;

        for(i=1;i<=n;i++)

            if(tch[i]!=Kmatch[i])

                k++;

        printf("%d %d\n",k,sum-ans);

    }

    return 0;

}


 

 

 

你可能感兴趣的:(HDU)