• 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
    ",k,sum-ans);
        }
        return 0;
    }


  • 相关阅读:
    find命令详解
    wget命令
    国内镜像源
    向linux服务器上传下载文件方式收集
    一些初学shell自己写的一些练习题脚本
    在Linux系统下mail命令的用法
    MAC 下安装 SVN
    天气预报api整理
    pdi vcard-2.1
    Android Studio 问题锦集【持续更新】
  • 原文地址:https://www.cnblogs.com/riskyer/p/3220309.html
Copyright © 2020-2023  润新知