powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пропорциональное распределение
16 сообщений из 41, страница 2 из 2
Пропорциональное распределение
    #39548882
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Да, по "горизонтали" и по "вертикали".
Необязательно на SQL, можно и на PL/SQL.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548887
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Cane Cat Fisher,

В Вашем алгоритме мне самым проблемным кажется шаг №2.
Представьте, отрядов 30 - 50, среди них есть "легкие", т.е. те, чей коэффициент мал. При распределении значительного количества типов объектов этого коэффициента может не хватать, чтобы получить объект любого конкретного типа, но в сумме на один, какой либо, объект хватает. Определить какой, можно только распределив все и посмотрев у какого типа остался "лишний" объект.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39548993
жонсноу
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Почему-то мне кажется, что это один из вариантов задачи о рюкзаке.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39549009
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSigОпределить какой, можно только распределив все и посмотрев у какого типа остался "лишний" объект.
если сразу распределить точно , то потом лишний может быть и не 1
напр
точно
0.4 0.4 0.4 0.4 - 4 распределили поровну но 10 частей с весом по 10
если округлим получим 10 нулей и неустойку 4
поетому сразу округлять и остаток распределять между оставшимсями

но опять же 4 еденички можно очень даже по разному расставить на 10мест


Код: plsql
1.
Обратите внимание, в приведенных мной примерах данных SUM(SQUAD.CNT) = SUM(OBJ.CNT), чтобы не усложнять задачу.



если условие убрать, то очень легко придумать случай когда распределить не удастся

нужны теоретики (или хотя-бы кто помнит что-то из дискретной)
является ли условие SUM(SQUAD.CNT) = SUM(OBJ.CNT) необходимым/достаточным ...

задачка скорее все известная (воможно имеет имя - типа пионерские рюбзаки)
тогда решение наверняка описано в той же вики


зы
заполнять матрицу и перебором подгонять результат, не считаю решением

.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39549059
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

Совершенно верно.
И таких, где 0.4, 0.4 и т.д., а в итоге все нули, на реальных данных несколько подразделений.

Про SUM(SQUAD.CNT) = SUM(OBJ.CNT) - в реальности подразделения имеют "вес" (численность), но привести этот "вес" к количеству предметов, зная их общее число, не сложная задача. Погрешность округления списывается на самые "толстые" подразделения. Все вполне объяснимо, заказчик понимает. А вот красиво распределить по типам, коих много и они имеют разную ценность, а количество предметов одного типа может быть относительно небольшим, у меня пока не получается. Сбрасывать погрешность в одно место, например, также, самым "толстым" подразделениям - не вариант, у них получается много, а у "худых" вообще ничего. В результате должен формироваться отчет, типа список подразделений с численностью, матрица вот этого распределения и "итого по строке", "итого по столбцу", т.е. перекосы будут очевидны.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39549099
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymSig,

Код: plsql
1.
Сбрасывать погрешность в одно место, например, также, самым "толстым" подразделениям - не вариант, у них получается много, а у "худых" вообще ничего.


погрешность не должна расти, она будет ити на пользу полстосумам (так договорились), но не больше +-0.5 (округляем, больше нікак не получітся)


самый простой пример если SUM(SQUAD.CNT) = SUM(OBJ.CNT) не выполняется

матрица 2х10 (распределить равномерно вес 10 по 10)
распределяем 4 -получаем 4 и 6 нулей
распределяем 92 - две 10 и 8 девяток
10 во всех столбцах никак не получить

можно попробовать
a)
1) формируем первую строку и сохраняем доп информацию по оруглению
-1 уменьшили, +1 увеличили 0-повезло (целое число)
2) в следующих строках не просто округляем, а с учетом как поступали в предыдущих
стараясь свести сумму еденичек к нулю

============

б)
для нечетных строк, если число стоит в нечетном столбце - ceil, в нечетном -floor
и наоборот
для четных строк, если число стоит в нечетном столбце - floor, в нечетном -ceil

с)
для нечетных строк, сортировка CNT DESC
для четных строк, сортировка CNT ASC

так по столбцах уменьшится накопление погрешности,
но точности всеравно не будет


зы
чувствую, что должен быть алгоритм, кроме перебора
.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550110
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
with s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by rest_squad desc, squad_id) rnmax               
        , sum(rest_squad) over (order by rest_squad desc, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt, rest_obj, row_number() over (order by rest_obj desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select b.obj_id
                , b.obj_cnt
                , row_number() over (order by rest_obj desc, obj_seq) rn
             from b
                , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
          )
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select c 
                                      from (select squad_id
                                                 , obj_id
                                                 , count(*) c 
                                              from s, b1
                                             where b1.rn between s.rnmin and s.rnmax
                                             group by squad_id
                                                 , obj_id
                                            ) a 
                                      where a.obj_id = o.id 
                                        and a.squad_id = s.squad_id),0) dst_cnt
     from s
        , obj o
    order by obj_id
        , squad_id  



на исходных данных проходят оба теста
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550120
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MazoHist,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
SQUAD (ID, CNT) as (
select 1, 5 from dual union all
select 2, 17 from dual union all
select 3, 19 from dual union all
select 4, 20 from dual union all
select 5, 16 from dual )
,OBJ (ID, CNT) as (
select 1, 52 from dual union all
select 2, 107 from dual union all
select 3, 7 from dual )

    OBJ_ID    OBJ_CNT   SQUAD_ID  SQUAD_CNT    DST_CNT
---------- ---------- ---------- ---------- ----------
         1         52          1          5          3
         1         52          2         17         11
         1         52          3         19         12
         1         52          4         20         13
         1         52          5         16         10
         2        107          1          5          6
         2        107          2         17         23
         2        107          3         19         26
         2        107          4         20         27
         2        107          5         16         22
         3          7          1          5          0
         3          7          2         17          1
         3          7          3         19          1
         3          7          4         20          1
         3          7          5         16          1



20924907

Код: plaintext
1.
2.
3.
4.
ID	| 1	| 2	| 3	| 4	| 5
1	| 2	| 11	| 16	| 9	| 14
2	| 3	| 23	| 32	| 19	| 30
3	| 0	| 1	| 3	| 1	| 2


.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550137
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stax,
решал для случая SUM(SQUAD.CNT) = SUM(OBJ.CNT)

Небольшая правка
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
with s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by squad_seq, squad_id) rnmax               
        , sum(rest_squad) over (order by squad_seq, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , greatest(squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj),0) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt
                , rest_obj
                , row_number() over (order by rest_obj desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select b.obj_id
                , b.obj_cnt
                , row_number() over (order by rest_obj desc, obj_seq) rn
             from b
                , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
          )
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select count(*) c 
                                       from s s2, b1
                                       where b1.rn between s.rnmin and s.rnmax
                                         and b1.obj_id = o.id 
                                         and s2.squad_id = s.squad_id                                       
                                       group by s2.squad_id
                                           , b1.obj_id
                                     ),0) dst_cnt
     from s
        , obj o
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550153
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати говоря. Последний вариант для SUM(OBJ.CNT) > SUM(SQUAD.CNT) работает по принципу
авторТрем самым толстым комсомольцам по груше, остальным не повезло..., т.е. "отряд не примет больше того что может унести", в обратном случае понятно - недостача, при распределении просто кончаются предметы.
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550167
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MazoHistStax,
решал для случая SUM(SQUAD.CNT) = SUM(OBJ.CNT)

Небольшая правка


не совсем пропорционально делит

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
with
SQUAD (ID, CNT) as (
select 1, 10 from dual union all
select 2, 10 from dual union all
select 3, 10 from dual union all
select 4, 10 from dual union all
select 5, 10 from dual )
,OBJ (ID, CNT) as (
select 1, 44 from dual union all
select 2, 4 from dual union all
select 3, 2 from dual )
SQL> /

    OBJ_ID    OBJ_CNT   SQUAD_ID  SQUAD_CNT    DST_CNT
---------- ---------- ---------- ---------- ----------
         1         44          1         10         10
         1         44          2         10         10
         1         44          3         10          8
         1         44          4         10          8
         1         44          5         10          8
         2          4          1         10          0
         2          4          2         10          0
         2          4          3         10          2
         2          4          4         10          2
         2          4          5         10          0
         3          2          1         10          0
         3          2          2         10          0
         3          2          3         10          0
         3          2          4         10          0
         3          2          5         10          2




имхо
надо
автор9 9 9 9 8
1 1 1 0 1
0 0 0 1 1



.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550179
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Подкрутил сортировку.
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
with s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by squad_seq, squad_id) rnmax               
        , sum(rest_squad) over (order by squad_seq, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , greatest(squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj),0) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt
                , rest_obj
                --, obj_id obj_seq
                , row_number() over (order by rest_obj desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select obj_id
                , row_number() over (order by rn) rn from (
                  (select b.obj_id
                        , row_number() over (partition by obj_id order by obj_seq desc, rest_obj desc) rn
                     from b
                        , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
                 )))
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select count(*) c 
                                       from s s2, b1
                                       where b1.rn between s.rnmin and s.rnmax
                                         and b1.obj_id = o.id 
                                         and s2.squad_id = s.squad_id                                       
                                       group by s2.squad_id
                                           , b1.obj_id
                                     ),0) dst_cnt
     from s
        , obj o
order by obj_id, squad_id        



получилось такое
12345198999210111302000

для 20924849 получилось такое
123451211169142323331929301213
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550184
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MazoHistПодкрутил сортировку.

получилось такое
12345198999210111302000



еще б 2-ку разбить на единички

но мож DymSig и етого будет достаточно

.....
stax
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550212
MazoHist
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Staxеще б 2-ку разбить на единички

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
with
SQUAD (ID, CNT) as (
select 1, 10 from dual union all
select 2, 10 from dual union all
select 3, 10 from dual union all
select 4, 10 from dual union all
select 5, 10 from dual )
,OBJ (ID, CNT) as (
select 1, 44 from dual union all
select 2, 4 from dual union all
select 3, 2 from dual )
, s as (
   select squad_id
        , squad_cnt
        , part
        , rest_squad 
        , sum(rest_squad) over (order by squad_seq, squad_id) rnmax               
        , sum(rest_squad) over (order by squad_seq, squad_id) - rest_squad+1 rnmin
     from ( select squad_id
                 , squad_cnt
                 , part
                 , row_number() over (order by part desc, squad_id) squad_seq
                 , greatest(squad_cnt - (SELECT sum(trunc(part*obj.cnt)) FROM obj),0) rest_squad 
              from (select id squad_id
                         , cnt squad_cnt
                         , ratio_to_report(cnt) over () part
                      from squad)))
   , b as (select obj_id
                , obj_cnt
                , rest_obj
                --, obj_id obj_seq
                , row_number() over (order by obj_part desc, obj_id) obj_seq 
             from (select o.id obj_id
                        , o.cnt obj_cnt
                        , ratio_to_report(cnt) over () obj_part
                        , O.CNT -(SELECT sum(trunc(part*o.cnt)) FROM S) rest_obj
                     from obj o))
  , b1 as (select obj_id
                , row_number() over (order by rn, obj_id) rn from (
                  (select b.obj_id
                        , row_number() over (partition by obj_id order by obj_id desc) rn
                     from b
                        , table(select cast(collect(1) as sys.odcinumberlist) from dual connect by level <= b.rest_obj)
                 )))
   select o.id obj_id
        , o.cnt obj_cnt
        , s.squad_id
        , s.squad_cnt
        , trunc(o.cnt*s.part) + nvl((select count(*) c 
                                       from s s2, b1
                                       where b1.rn between s.rnmin and s.rnmax
                                         and b1.obj_id = o.id 
                                         and s2.squad_id = s.squad_id                                       
                                       group by s2.squad_id
                                           , b1.obj_id
                                     ),0) dst_cnt
     from s
        , obj o
order by obj_id, squad_id        
        



12345199899210111301100

на [msg_id=20924907] дает результат чуть хуже
1234511101610152423331829302212

играясь row_number() в b1 можно корректировать
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39550376
жонсноу
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MazoHist,

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
with
SQUAD (ID, CNT) as (
select 1, 1 from dual union all
select 2, 2 from dual union all
select 3, 3 from dual)
,OBJ (ID, CNT) as (
select 1, 3 from dual union all
select 2, 2 from dual union all
select 3, 1 from dual)

o\s123110220113010
а ожидается:
o\s123111120113001
...
Рейтинг: 0 / 0
Пропорциональное распределение
    #39551015
DymSig
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MazoHist,

Прошу прощения за молчание, отвлекали на другие задачи.

По поводу решения - снимаю шляпу, здорово получилось, спасибо!
...
Рейтинг: 0 / 0
16 сообщений из 41, страница 2 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Пропорциональное распределение
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]