如何在 javascript 中使用缓冲区实现公平划分(?)?
How to implement fair division(?) with buffer in javascript?
为了便于解释,假设我有 101 个实体。实体都是人。
在第一个实体中,它有x个"potatoes",我想要它有y个土豆,现在我以950为例,故意选择一个比1000更尴尬的数字来测试。
var personOne = {
...
potatoes: 100
}
我还有 100 个这样的实体,它们可能有任意数量的土豆,但为了再次举例,我设置了一个至少 100 个的常量缓冲区 - 必须与每个人保持一致。
这意味着对于拥有超过 100 个的所有实体,我将从他们那里拿走一些 - 我希望这在所有实体之间按比例共享,这样 850 个就不会从前两三个中拿走, 但从所有能够提供这样数量的人中提取 10 或 5 个。
对方法有什么想法吗?
可选:我使用的属性多于一个 "potatoes" 属性,但我计划遍历每种类型并重新使用我为每种类型找到的方法。我不确定这是否会影响答案。
重要/简化
一个实体正在从所有其他实体中拉取 "potatoes",它们并没有均匀分布在所有实体中——它们被带到一个实体中。我只是不想以一种与所有其他 100 个实体不成比例的方式来做。
这比切蛋糕还多。我正在努力 google 或想出数学问题的正确名称。
案例一、每人100个以上的土豆:把所有的土豆放在一起,平分。
情况2. 土豆不够大家吃100个,把超过100个的加起来 + 把不足100个的所有土豆加起来,分100以下的土豆。
(是的,案例 2 意味着一些 100 岁以下的人最终得到的土豆比他们开始时少。这不公平?好吧,如果没有足够多的人,也许你不应该保护 1% 的人那么多每个人的土豆 :) 但我离题了)
希望这次我理解了问题所在。我会计算获得所需数量的土豆所需的多余土豆的百分比,并取每个参与者多余土豆的百分比,或者如果总数不足,则取全部。
这里有一些演示代码来澄清。它可能过于冗长,但无论如何只能用来表明意图。我假设有一个非常精确的土豆切割器可用,因为没有关于如何处理四舍五入的规定。输出是参与者在重新分配之前和之后的土豆。我将 NUMBER_OF_PARTICIPANTS
设置为 4
所以输出有点可读。
const MAXIMUM_START_POTATOES = 1234;
const MINIMUM_KEPT_POTATOES = 100;
const ENTITY_TAKING_POTATOES = 0;
const DESIRED_POTATOES = 950;
const NUMBER_OF_PARTICIPANTS = 4;
//generate NUMBER_OF_PARTICIPANTS entities with random amount of potatoes
let entities = [];
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
entities.push(Math.floor(Math.random() * (MAXIMUM_START_POTATOES + 1)));
}
console.log(entities);
let required_potatoes = DESIRED_POTATOES - entities[ENTITY_TAKING_POTATOES];
if (required_potatoes <= 0) console.log("nothing to do.");
else {
let excess_potatoes = 0;
//Sum excess available potatoes
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
if (i === ENTITY_TAKING_POTATOES) continue;
excess_potatoes += Math.max(0, entities[i] - MINIMUM_KEPT_POTATOES);
}
if (excess_potatoes < required_potatoes) {
//just take all excess potatoes
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
if (i === ENTITY_TAKING_POTATOES) continue;
entities[i] = Math.min(entities[i], MINIMUM_KEPT_POTATOES);
}
entities[ENTITY_TAKING_POTATOES] += excess_potatoes;
} else {
//calculate percentage of the excess potatoes that is needed
let percentage_required = required_potatoes / excess_potatoes;
//Take that percentage off every participant's excess potatoes
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
if (i === ENTITY_TAKING_POTATOES) continue;
entities[i] -= Math.max(0, entities[i] - MINIMUM_KEPT_POTATOES) * percentage_required;
}
//Assume double precision is enough for this to never be an issue
entities[ENTITY_TAKING_POTATOES] = DESIRED_POTATOES;
}
console.log(entities);
}
为了便于解释,假设我有 101 个实体。实体都是人。
在第一个实体中,它有x个"potatoes",我想要它有y个土豆,现在我以950为例,故意选择一个比1000更尴尬的数字来测试。
var personOne = {
...
potatoes: 100
}
我还有 100 个这样的实体,它们可能有任意数量的土豆,但为了再次举例,我设置了一个至少 100 个的常量缓冲区 - 必须与每个人保持一致。
这意味着对于拥有超过 100 个的所有实体,我将从他们那里拿走一些 - 我希望这在所有实体之间按比例共享,这样 850 个就不会从前两三个中拿走, 但从所有能够提供这样数量的人中提取 10 或 5 个。
对方法有什么想法吗?
可选:我使用的属性多于一个 "potatoes" 属性,但我计划遍历每种类型并重新使用我为每种类型找到的方法。我不确定这是否会影响答案。
重要/简化
一个实体正在从所有其他实体中拉取 "potatoes",它们并没有均匀分布在所有实体中——它们被带到一个实体中。我只是不想以一种与所有其他 100 个实体不成比例的方式来做。
这比切蛋糕还多。我正在努力 google 或想出数学问题的正确名称。
案例一、每人100个以上的土豆:把所有的土豆放在一起,平分。
情况2. 土豆不够大家吃100个,把超过100个的加起来 + 把不足100个的所有土豆加起来,分100以下的土豆。
(是的,案例 2 意味着一些 100 岁以下的人最终得到的土豆比他们开始时少。这不公平?好吧,如果没有足够多的人,也许你不应该保护 1% 的人那么多每个人的土豆 :) 但我离题了)
希望这次我理解了问题所在。我会计算获得所需数量的土豆所需的多余土豆的百分比,并取每个参与者多余土豆的百分比,或者如果总数不足,则取全部。
这里有一些演示代码来澄清。它可能过于冗长,但无论如何只能用来表明意图。我假设有一个非常精确的土豆切割器可用,因为没有关于如何处理四舍五入的规定。输出是参与者在重新分配之前和之后的土豆。我将 NUMBER_OF_PARTICIPANTS
设置为 4
所以输出有点可读。
const MAXIMUM_START_POTATOES = 1234;
const MINIMUM_KEPT_POTATOES = 100;
const ENTITY_TAKING_POTATOES = 0;
const DESIRED_POTATOES = 950;
const NUMBER_OF_PARTICIPANTS = 4;
//generate NUMBER_OF_PARTICIPANTS entities with random amount of potatoes
let entities = [];
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
entities.push(Math.floor(Math.random() * (MAXIMUM_START_POTATOES + 1)));
}
console.log(entities);
let required_potatoes = DESIRED_POTATOES - entities[ENTITY_TAKING_POTATOES];
if (required_potatoes <= 0) console.log("nothing to do.");
else {
let excess_potatoes = 0;
//Sum excess available potatoes
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
if (i === ENTITY_TAKING_POTATOES) continue;
excess_potatoes += Math.max(0, entities[i] - MINIMUM_KEPT_POTATOES);
}
if (excess_potatoes < required_potatoes) {
//just take all excess potatoes
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
if (i === ENTITY_TAKING_POTATOES) continue;
entities[i] = Math.min(entities[i], MINIMUM_KEPT_POTATOES);
}
entities[ENTITY_TAKING_POTATOES] += excess_potatoes;
} else {
//calculate percentage of the excess potatoes that is needed
let percentage_required = required_potatoes / excess_potatoes;
//Take that percentage off every participant's excess potatoes
for (let i = 0; i < NUMBER_OF_PARTICIPANTS; i++) {
if (i === ENTITY_TAKING_POTATOES) continue;
entities[i] -= Math.max(0, entities[i] - MINIMUM_KEPT_POTATOES) * percentage_required;
}
//Assume double precision is enough for this to never be an issue
entities[ENTITY_TAKING_POTATOES] = DESIRED_POTATOES;
}
console.log(entities);
}