【问题标题】:Fair product distribution algorithm公平的产品分配算法
【发布时间】:2011-05-07 03:59:35
【问题描述】:

这是我的问题:

  • 有 n 家公司经销 产品。
  • 所有产品应在 k 天内分发
  • Ci公司的产品配送应该是连续的——也就是说可以在2、3、4、5天配送,但不能在2、3、6、7天配送
  • Ci 公司在第 j 天分发的产品数量应少于(或等于)第 j-1 天(如果在第 j-1 天有的话)
  • 第 i 天和第 j 天分发的产品之间的差异不应大于 1

例子:

我们有 3 天的时间来分发产品。 A公司的产品:a,a,a,a,a。 B公司的产品:b,b,b。 C公司产品:c,c

公平分配: [aab,aabc,abc]

分配无效: [aabc,aabc,ab] 因为第 1 天有 4 个产品,第 3 天有 2 个产品(差异 > 1)

分配无效: [abc,aabc,aab] 因为第 1 天有 1 个产品 A,第 2 天有 2 个产品 A,所以产品 A 的分布不是非递减的

编辑 如果有无法公平分配的情况,请提供简短描述,我会接受答案

【问题讨论】:

  • 您似乎错过了一个特殊情况:公司 Ci 在第 j 天分发的产品数量应少于第 j-1 天,但在您的公平示例中,“c”为零"s 在第一天和第一天 "c" 在第二天。
  • 您的意思是小于或等于而不是小于您的第 4 个要点?
  • 一天分发的产品数量是否有最大限制?否则为什么不在第一天分发所有公司的所有产品?
  • 第五点:分配公平,天差不大于1
  • @belisarius:不,我现在明白了,在任何一天分发的产品总数最多可以变化 1 个。 (这就是 OP 的第 5 点所说的,尽管相当抽象——想象一下句子开头的“对于任何日子 i 和 j”。)

标签: algorithm distribution set bin-packing


【解决方案1】:

我不认为你总能满足你的要求。

考虑 4 天,供应商 A 提供 6 件商品,供应商 B 提供 6 件商品。

【讨论】:

  • [a,a,a][a,a,a][b,b,b][b,b,b] 还是我错过了什么?
  • 3天,A的7件,B的5件怎么样?
  • [b,b,b,b,b][a,a,a,a][a,a,a] 还是我又错过了什么?我正在寻找自己无法解决的案例,但仍然没有运气......
  • @mcveat:失败,因为第 1 天有 5 个产品,而第 3 天有 3 个产品,并且任何 2 天之间的差异最多为 1。
【解决方案2】:

Gareth Rees 对 djna 答案的评论是正确的——以下反例无法解决

  • 3 天,A 公司 7 件商品和 B 公司 5 件商品

我使用以下最愚蠢的蛮力 Perl 程序对此进行了测试(尽管效率非常低,但它需要不到一秒钟的时间):

my ($na, $nb) = (7, 5);
for (my $a1 = 0; $a1 <= $na; ++$a1) {
    for (my $a2 = 0; $a2 <= $na - $a1; ++$a2) {
        my $a3 = $na - $a1 - $a2;
        for (my $b1 = 0; $b1 <= $nb; ++$b1) {
            for (my $b2 = 0; $b2 <= $nb - $b1; ++$b2) {
                my $b3 = $nb - $b1 - $b2;
                if ($a1 >= $a2 && $a2 >= $a3 || $a1 == 0 && $a2 >= $a3 || $a1 == 0 && $a2 == 0) {
                    if ($b1 >= $b2 && $b2 >= $b3 || $b1 == 0 && $b2 >= $b3 || $b1 == 0 && $b2 == 0) {
                        if (max($a1 + $b1, $a2 + $b2, $a3 + $b3) - min($a1 + $b1, $a2 + $b2, $a3 + $b3) <= 1) {
                            print "Success! ($a1,$a2,$a3), ($b1,$b2,$b3)\n";
                        }
                    }
                }
            }
        }
    }
}

请查看并确认我没有犯任何愚蠢的错误。 (为简洁起见,我省略了 max()min() —— 它们只是按照您的预期行事。)

【讨论】:

  • {a,a,a,a,a} {a,b,b,b} {a,b,b} 无效吗?
  • @belisarius:是的,它违反了第五个条件(5-3 > 1)。
  • @belisarius,是的,请参阅问题中无效分布的示例,示例 1 AND 示例 2
  • @Unreason 条件 3 满足 -> 连续天数。满足条件 4 -> 按公司减少产品数量(非严格)。满足条件 6 -> 产品总数逐日减少(5,4 和 3)
  • @Matthiew 查看之前的评论
【解决方案3】:

已经证明第 4 点和第 5 点不兼容:

  • 4:对于任何一天 j,对于任何公司 A,C(j,A) == 0 或 C(j,A) >= C(j+1,A)
  • 5:对于任何天 i 和 j,|C(i) - C(j)| &lt;= 1

因此,您需要放松任何一个约束。老实说,虽然我对为什么设置4 有所了解(以避免无限期延迟一家公司的分发),但我认为可以以其他方式表达将分发的第一天和最后一天视为特殊的(因为在第一天,你通常拿走前一家公司剩下的东西,最后一天你分发剩下的东西)。

第 3 点确实强制了连续性。

数学上:

对于任何有产品的公司 A,存在两天 i 和 j 使得:

  • C(i,A) > 0 和 C(j,A) > 0
  • 对于任何一天 x 使得 x j,C(x,A) = 0
  • 对于任何一天 x 满足 i

诚然,这个问题很容易解决:)

【讨论】:

    【解决方案4】:

    因为我觉得这个问题很有趣,所以我做了一个模型来使用MiniZinc寻找解决方案。使用Gecode 后端,初始示例显示在大约 1.6 毫秒内有 20 个解决方案。

    include "globals.mzn";
    
    %%% Data
    % Number of companies
    int: n = 3;
    % Number of products per company
    array[1..n] of int: np = [5, 3, 2];
    % Number of days
    int: k = 3;
    
    %%% Computed values
    % Total number of products
    int: totalnp = sum(np);
    % Offsets into products array to get single companys products 
    % (shifted cumulative sum).
    array[1..n] of int: offset = [sum([np[j] | j in 1..i-1]) 
                              | i in 1..n];
    
    %%% Predicates
    predicate fair(array[int] of var int: x) =
          let { var int: low,
                var int: high
          } in
            minimum(low, x) /\
            maximum(high, x) /\
            high-low <= 1;
    predicate decreasing_except_0(array[int] of var int: x) =
            forall(i in 1..length(x)-1) (
                     (x[i] == 0) \/
                     (x[i] >= x[i+1])
            );
    predicate consecutive(array[int] of var int: x) =
            forall(i in 1..length(x)-1) (
                 (x[i] == x[i+1]) \/
                 (x[i] == x[i+1]-1)
            );
    
    %%% Variables
    % Day of production for all products from all companies
    array[1..totalnp] of var 1..k: products 
              :: is_output;
    % total number of products per day
    array[1..k] of var 1..totalnp: productsperday 
            :: is_output;
    
    %%% Constraints 
    constraint global_cardinality(products, productsperday);
    constraint fair(productsperday);
    constraint
        forall(i in 1..n) (
             let { 
                 % Products produced by company i
                 array[1..np[i]] of var int: pi
                    = [products[j] | 
                     j in 1+offset[i]..1+offset[i]+np[i]-1],
                 % Products per day by company i
                 array[1..k] of var 0..np[i]: ppdi
             } in
               consecutive(pi) /\
               global_cardinality(pi, ppdi) /\
               decreasing_except_0(ppdi)
        );
    
    %%% Find a solution, default search strategy
    solve satisfy;
    

    谓词decreasing_except_0consecutive 都非常幼稚,并且分解很大。要解决更大的实例,可能应该用更智能的变体替换它们(例如通过使用常规约束)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      相关资源
      最近更新 更多