_대문 | 방명록 | 최근글 | 홈피소개 | 주인놈
FrontPage › 작업할당최적화문제
[[TableOfContents]

커뮤니티에 아래와 같은 [http]질문이 올라왔다.
재미있을 것 같아 해봤다.

문제 #

오더번호    규격    오더길이   만들개수    작업자
E	        1	    50	        7	
D	        3	    80	        6	
B	        1	    30	        1	
F	        3	    100	        15	
A	        2	    100	        10	
C	        1	    40	        4	

위의 자료를 가지고 작업자(홍길동,강감찬....)를 배정 할려고 합니다.

배정하는 원칙은 

첫번째, 작업자별로 오더의 길이의 합이 슷하도록 하여 나누어야 하며,
두번째, 작업난이도를 분류하여 작업자별로 슷하게 배분되어야 합니다.

해당 오더의 작업난이도는
1. 규격(1~3 / 클수록 작업이 어려움)
2. 오더길이/만들개수 = 제품의길이 (제품의 길이가 짧을수록 작업이 어려움)

위 두가지를 고려합니다.

규격에 따른 작업 난이도는 1~3까지 정해져 있고,  제품의 길이는 오더길이와 만들개수로 정해집니다.

설명이 제대로 전달되었는지 모르겠네요..

물론 최종적 디테일한 부분은 응용프로그램으로 구현이 되겠지만

최적화된 기본 쿼리가 언뜻 생각이 나지 않네요 
고수분들의 조언을 구해 봅니다.

솔루션 #

최적화 문제다. 유사도 개념을 이용하여 시뮬레이션 하면 쉽게 최적화 할 수 있다.
--데이터 만들기
;with temp(오더번호, 규격, 오더길이, 만들개수)
as
(
select 'A', 2, 100, 10 union all
select 'B', 1, 30 , 1  union all
select 'C', 1, 40 , 4  union all
select 'D', 3, 80 , 6  union all
select 'E', 1, 50 , 7  union all
select 'F', 3, 100, 15
)
select * into #temp
from temp

select N'홍길동' name into #worker union all
select N'강감찬' union all
select N'이순신' 



--simulation
--similarity, euclidean distance
set nocount on
if object_id('tempdb.dbo.#result') is not null
        drop table #result

create table #result(
    오더번호 nvarchar(200)
,   규격 int
,   오더길이 int
,   만들개수 int
,   작업자 nvarchar(200)
)

declare 
    @i int
,   @dist float
,   @min_dist float
set @i = 1

while(@i <= 100)
begin
    if object_id('tempdb.dbo.#rand') is not null
        drop table #rand

    select
        a.오더번호
    ,   a.규격
    ,   a.오더길이
    ,   a.만들개수
    ,   b.작업자
    ,   b.num
    into #rand
    from (select *, row_number() over(order by newid()) - 1 num from #temp) a
        inner join (    
            select 
                name 작업자
            ,   row_number() over(order by newid()) - 1 num
            ,   count(*) over() cnt
            from #worker 
        ) b
            on a.num % b.cnt = b.num

    declare
        @v1 float
    ,   @v2 float
    ,   @v3 float

    select 
        @v1 = sum(규격)
    ,   @v2 = sum(오더길이)
    ,   @v3 = sum(만들개수)
    from #rand
    where num = 0

    select @dist = sqrt(sum(n)) 
    from (
        select
            power(@v1 - sum(규격), 2) + power(@v2 - sum(오더길이), 2) + power(@v3 - sum(만들개수), 2) n
        from #rand
        where num <> 0
        group by
            num
    ) t

    if @i = 1 
    begin
        insert #result
        select
            오더번호
        ,   규격
        ,   오더길이
        ,   만들개수
        ,   작업자
        from #rand
        set @min_dist = @dist
    end else
    begin
        if @min_dist > @dist
        begin
            truncate table #result
            insert #result
            select
                오더번호
            ,   규격
            ,   오더길이
            ,   만들개수
            ,   작업자
            from #rand

            set @min_dist = @dist
        end
    end
    --print @i
    set @i = @i + 1
end

print @min_dist
select 
    오더번호
,   규격
,   오더길이 * 1.0 / 만들개수 [오더길이/만들개수]
,   작업자    
from #result
order by 작업자

결과
오더번호    규격    오더길이/만들개수   작업자
E	        1	    7.142857142857	    강감찬
D	        3	    13.333333333333	    강감찬
A	        2	    10.000000000000	    이순신
C	        1	    10.000000000000	    이순신
B	        1	    30.000000000000	    홍길동
F	        3	    6.666666666666	    홍길동
EditText : Print : Mobile : FindPage : DeletePage : LikePages : Powered by MoniWiki : Last modified 2018-04-13 23:12:53

마음이 열린 사람이 껴안지 못할 현실이란 없다. 불가능이란 깨달은 이에게 이미 존재하지 않는다.