zoukankan      html  css  js  c++  java
  • poj 3686 The Windy's( KM算法 )

    恩 , 题是好题 , 一道经典KM算法题 , 只是刚开始读错题了,感觉思路没错但就是过不了样例,受不了了就上网查了一下题意,果然题意理解错了 ,改了一下输入,又加了个标记数组就这样的过了~  唉,由此可以看出学好英语是多么的重要!

    题目大意是:有N个订单要在M个机器上加工,有一个N*M的矩阵描述其加工时间,同一时间内每台机器只能加工一个订单,问加工完所有订单后,时的平均时间最小。

    思路就是:

    将订单作为二分图中X部的点,总共N个。

    将每个机器拆成N个点作为二分图中Y部的点,总共N*M个。

    第J个机器的第P个点代表,使用机器 J进行倒数第P次加工。

    假设我们按顺序在J机器上工件i1 , i2 , i3.....ik个工件,则总共需要花费i1*k + i2*(k-1) + i3*(k-2) +......+ ik*1;

    所以我们对于X中每个点I,Y中每个点(J,P),连接一条hour[I,J]*P权值的边。

    接下来进行二分图最佳匹配即可。

    不过还是有收获的,至少对KM算法有了一点新的认识,KM算法类似于求图的最短路,只不过这个图要是二分图,并且两个点之间不能有其他的点,然后就是和求最短路一样的套用模板了。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <algorithm>
    #include <iostream>
    #define maxx 55
    #define INF 0xffffff
    using namespace std;
    
    int mm[maxx][maxx*maxx] , hour[maxx][maxx] ;
    int lx[maxx] , ly[maxx*maxx] ;
    int vistx[maxx] , visty[maxx*maxx] ;
    int linkx[maxx*maxx] , linky[maxx*maxx] ;
    int N , M ;
    
    void init()
    {
        int i , j , k ;
        
        memset( hour , 0 , sizeof ( hour ));
        memset( mm , 0 , sizeof ( mm ));
        
        for ( i = 0 ; i < N ; i++ )
        for ( j = 0 ; j < M ; j++ )
        scanf ( "%d", &hour[i][j] );
        
        for ( i = 0 ; i < N ; i++ )//处理输入,将M台机器每台分为N份
        for ( j = 0 ; j < M ; j++ )
        for ( k = 0 ; k < N ; k++ )
        mm[i][j*N+k] = hour[i][j] * ( k+1 );
        
        M = N * M ;//二分图中Y集中共有N*M个点
        
        memset( lx , 127 , sizeof ( lx ));//将X集中点的顶标置为最大
        memset( ly , 0 , sizeof ( ly ));
        
        for ( i = 0 ; i < N ; i++ )
        for ( j = 0 ; j < M ; j++ )
        if ( mm[i][j] < lx[i] )
        lx[i] = mm[i][j] ;//初始化X集中点的顶标
    }
    
    int find ( int x )
    {
        int i ;
        vistx[x] = 1;
        for ( i = 0 ; i < M ; i++ )
        if ( !visty[i] && lx[x] + ly[i] == mm[x][i] )
        {
            visty[i] = 1 ;
            if ( linkx[i] == -1 || find ( linkx[i] ))
            {
                linkx[i] = x;
                linky[x] = i ;
                return 1;
            }
        }
        return 0;
    }
    
    void KM()
    {
        int i  , j , k ;
        
        memset( linkx , -1 , sizeof ( linkx ));
        memset( linky , -1 , sizeof ( linky ));
        
        for ( i = 0 ; i < N ; i++ )
        {
    
            while ( 1 )
            {
                memset( vistx , 0 , sizeof ( vistx ));
                memset( visty , 0 , sizeof ( visty ));
                if ( find ( i ))//判断是否为完美匹配
                break;
                int minn = INF ;
                for ( j = 0  ; j < N ; j++ )
                if ( vistx[j] )
                {
                    for ( k = 0 ; k < M ; k++ )
                    if ( !visty[k] && mm[j][k] - lx[j] - ly[k] < minn )
                    minn = mm[j][k] - lx[j] - ly[k] ;
                }
                for ( j = 0 ; j < N ; j++ )//调整顶标
                if ( vistx[j] )
                lx[j] += minn ;
                for ( j = 0 ; j < M ; j++ )
                if ( visty[j] )
                ly[j] -=minn ;
            }
        }
        
        int sum = 0;
        for ( i = 0 ; i < N ; i++ )
        sum += mm[i][linky[i]];
        //cout<<sum<<endl;
        printf ( "%.6lf\n" , 1.0 * sum / N );
    }
    
    int main()
    {
        int cas ;
    
        scanf ( "%d" , &cas );
        while ( cas-- )
        {
            scanf ( "%d%d" , &N , &M );
            init();
            KM();
        }
        return 0;
    }
  • 相关阅读:
    vue+springboot+element+vue-resource实现文件上传
    使用bfg快速清理git历史大文件
    git clone异常 【fatal: protocol error: bad line length character: Inte】
    excel 一次删除所有空行
    vim编辑器
    prometheus安装
    递归计算分波那契数列和阶乘
    如何理解线程安全?
    创建线程的方式
    为什么说一个对象是线程安全的?
  • 原文地址:https://www.cnblogs.com/misty1/p/2508980.html
Copyright © 2011-2022 走看看