zoukankan      html  css  js  c++  java
  • P

    分析:这是一个KM的模板题,也就不多说了,KM最复杂的情况都能过,下面是没有优化过的代码:
    ************************************************************
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;

    const int MAXN = 305;
    const int oo = 1e9+7;

    int w[MAXN][MAXN], N;
    int dx[MAXN], dy[MAXN];
    int Ly[MAXN], slack[MAXN];
    bool vx[MAXN], vy[MAXN];

    bool Find(int i)
    {///别忘记vx[i]赋值true,表示可以增广的时候达到了i点
        vx[i] = true;
        for(int j=1; j<=N; j++)
        {
            if( !vy[j] && dx[i]+dy[j] == w[i][j] )
            {
                vy[j] = true;

                if( !Ly[j] || Find(Ly[j]) )
                {
                    Ly[j] = i;
                    return true;
                }
            }
            ///else if(vy[j] == false)
               
    /// slack[j] = min(slack[j], dx[i]+dy[j]-w[i][j]);
        }

        return false;
    }
    int KM()
    {
        int i, j, k;

        for(i=1; i<=N; i++) while(1)
        {///给每个点进行增广,找不到减去一个d,继续找

            memset(vx, falsesizeof(vx));
            memset(vy, falsesizeof(vy));

            if( Find(i) == truebreak;

            int d = oo;

            for(j=1; j<=N; j++) if( vx[j] )
            for(k=1; k<=N; k++) if( !vy[k] )
            {///用访问过的左边和未访问过的右边求出来一个最小的d
                d = min( d,  dx[j]+dy[k]-w[j][k]);
            }

            for(j=1; j<=N; j++)
            {///左边的标杆减去d,右边的加上d,这样原来匹配的值没有改变
             
    ///减去d的目的是为了查找那个可以增广的边里面最大的那个
                if(vx[j])dx[j] -= d;
                if(vy[j])dy[j] += d;
            }
        }

        int sum = 0;

        for(i=1; i<=N; i++)
        {
            sum += w[ Ly[i] ][i];
        }

        return sum;
    }

    int main()
    {
        while(scanf("%d", &N) != EOF)
        {
            memset(dx, falsesizeof(dx));
            memset(dy, falsesizeof(dy));
            memset(Ly, falsesizeof(Ly));

            for(int i=1; i<=N; i++)
            for(int j=1; j<=N; j++)
            {
                scanf("%d", &w[i][j]);
                dx[i] = max(dx[i], w[i][j]);
            }

            printf("%d ", KM());
        }

        return 0;
    }
    View Code
    *********************************************************************
    下面是优化过的,感觉时间上减少的不是那么明显,少了100多ms
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;

    const int MAXN = 305;
    const int oo = 1e9+7;

    int w[MAXN][MAXN], N;
    int dx[MAXN], dy[MAXN];
    int Ly[MAXN], slack[MAXN];
    bool vx[MAXN], vy[MAXN];

    bool Find(int i)
    {///别忘记vx[i]赋值true,表示可以增广的时候达到了i点
        vx[i] = true;
        for(int j=1; j<=N; j++)
        {
            if( !vy[j] && dx[i]+dy[j] == w[i][j] )
            {
                vy[j] = true;

                if( !Ly[j] || Find(Ly[j]) )
                {
                    Ly[j] = i;
                    return true;
                }
            }
            else if(vy[j] == false)
                slack[j] = min(slack[j], dx[i]+dy[j]-w[i][j]);
        }

        return false;
    }
    int KM()
    {
        int i, j;

        for(i=1; i<=N; i++)
        {
            for(j=1; j<=N; j++)
                slack[j] = oo;

            while(true)
            {
                memset(vx, falsesizeof(vx));
                memset(vy, falsesizeof(vy));

                if( Find(i) == true )break;

                int d = oo;

                for(j=1; j<=N; j++)
                {
                    if(!vy[j] && d > slack[j])
                        d = slack[j];
                }

                for(j=1; j<=N; j++)
                {
                    if(vx[j])dx[j] -= d;
                    if(vy[j])dy[j] += d;
                    else slack[j] -= d;
                }
            }
        }

        int sum = 0;

        for(i=1; i<=N; i++)
        {
            sum += w[ Ly[i] ][i];
        }

        return sum;
    }

    int main()
    {
        while(scanf("%d", &N) != EOF)
        {
            memset(dx, falsesizeof(dx));
            memset(dy, falsesizeof(dy));
            memset(Ly, falsesizeof(Ly));

            for(int i=1; i<=N; i++)
            for(int j=1; j<=N; j++)
            {
                scanf("%d", &w[i][j]);
                dx[i] = max(dx[i], w[i][j]);
            }

            printf("%d ", KM());
        }

        return 0;
    }
    View Code
  • 相关阅读:
    linux sleep用法
    linux下set命令的参数及用法
    给vim编辑器自动添加行号
    linux一些基本常识(三)
    shell脚本面试题
    linux下字符串的比较方式
    浅谈Windows API编程
    WIN32 API ------ 最简单的Windows窗口封装类
    Microsoft函数调用约定
    Android UI 设计规范
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4706346.html
Copyright © 2011-2022 走看看