用于确定共享项

时间:2017-09-12 14:29:22

标签: algorithm language-agnostic

假设我们想要从4套S1-S4中取出物品。集合在它们之间共享项目。一些示例集将是:

S1 = ['b1'];
S2 = ['b1', 'b2'];
S3 = ['b1', 'b2', 'b3'];
S4 = ['b1', 'b2', 'b3', 'b4'];

很明显,如果您从S1b1)中选择一项,那么您只能选择S2中的1项,S3中的2项和来自S4的3项S4

但是,如果您从S1中选择一项,那么在下一步中,您可以从S2 中选择所有项目或来自S3 <的所有项目strong>或来自b4的所有项目,只是因为算法必须足够聪明才能知道存在组合(例如,从S4分配b4),这将允许来自其他集合的最高免费元素数量较高(通过选择S3 S2中的最大免费3,S1中的2和S5中的1

换句话说,算法,当你占用一个元素中的一个元素时,不应该占用一个特定的元素,而是足够聪明,知道有多少元素(最大数量)可以考虑到以聪明的方式挑选物品,可以从其他套装中占用。

演示它应该如何工作(绿色=可用,红色=占用,橙色=由于来自另一组的占用而被占用):

enter image description here

另一个示范:

enter image description here (请注意,该算法发现S5有3个唯一元素,因此任何其他集合都是完全免费的)

还有一个:

enter image description here (请注意,算法理解如果你从S5中选择全部4,那么你必须放弃其他类别中的一个)

另一个:

enter image description here(如果您从S2中选择3项,则必须放弃S2中的1项,现在您最多只能从中拾取2个元素。请注意b1中的已占用项目不是特定元素,它是b7nodejs,它并不重要,我只对什么感兴趣我现在可以从中挑选的最大元素数量)

上述所有工作都适用于我的算法,但在其他情况下失败。

我到目前为止所尝试的内容(var allCategories = []; const process = require('process'); Reset = '\x1b[0m' FgRed = '\x1b[31m' FgGreen = '\x1b[32m' FgYellow = '\x1b[33m' function getCommonCount(s1, s2) { return s1.filter((n) => s2.includes(n)).length; } var categories = {}; var common = {}; function processCategories() { categories = {}; for (var i in allCategories) { categories[i] = { total: allCategories[i].length, occupied: 0, dueTo: {}, totalDue: 0 }; common[i] = {}; for (var j in allCategories) { if (i === j) { continue; } common[i][j] = getCommonCount(allCategories[i], allCategories[j]); } } } function occupy(countToOccupy, categoryId) { console.log('OCCUPY', countToOccupy, 'from', categoryId); var category = categories[categoryId]; var free = category.total - category.occupied; if (free < countToOccupy) { console.log('Cannot occupy that many elements of type', categoryId); return false; } category.occupied += countToOccupy; for (var otherCategoryId in common[categoryId]) { var commonCount = common[categoryId][otherCategoryId]; var atLeastThatMustOccupied = (category.occupied + commonCount) - category.total; if (atLeastThatMustOccupied < 0) { continue; }; var otherCategory = categories[otherCategoryId]; if (otherCategory.occupied < atLeastThatMustOccupied) { var countToOccupyOtherCategory = atLeastThatMustOccupied - otherCategory.occupied; otherCategory.occupied += countToOccupyOtherCategory; if (!otherCategory.dueTo.hasOwnProperty(categoryId)) { otherCategory.dueTo[categoryId] = 0; } otherCategory.dueTo[categoryId] += countToOccupyOtherCategory; otherCategory.totalDue += countToOccupyOtherCategory; } } return true; } function deoccupy(countToDeoccupy, categoryId) { console.log('DEOCCUPY', countToDeoccupy, 'from', categoryId); var category = categories[categoryId]; var reallyOccupied = (category.occupied - category.totalDue); if (reallyOccupied < countToDeoccupy) { console.log('There are not that much really occupied thingies here so as to deoccupy them'); return false; } category.occupied -= countToDeoccupy; for (var otherCategoryId in common[categoryId]) { if (!categories[otherCategoryId].dueTo.hasOwnProperty(categoryId)) { continue; // no elements set due to the parent category } var dueToNumber = categories[otherCategoryId].dueTo[categoryId]; var countToRemove = Math.min(countToDeoccupy, dueToNumber); if (countToRemove === dueToNumber) { // remove the dueTo field delete categories[otherCategoryId].dueTo[categoryId]; } else { categories[otherCategoryId].dueTo[categoryId] -= countToRemove; } categories[otherCategoryId].totalDue -= countToRemove; categories[otherCategoryId].occupied -= countToRemove; } return true; } function visualizeCategories() { process.stdout.write(Reset); console.log() for (let categoryId in categories) { var category = categories[categoryId]; var reallyOccupied = (category.occupied - category.totalDue); var free = category.total - category.occupied; process.stdout.write(FgGreen + categoryId + ' '); process.stdout.write(FgRed + '0'.repeat(reallyOccupied)); process.stdout.write(FgYellow + '0'.repeat(category.totalDue)); process.stdout.write(FgGreen + '0'.repeat(free)); console.log() } console.log(Reset); } allCategories = { S1: ['b1'], S2: ['b1', 'b2'], S3: ['b1', 'b2', 'b3'], S4: ['b1', 'b2', 'b3', 'b4'], S5: ['b5', 'b1', 'b7', 'b8'] }; console.log('CATEGORIES:'); console.log(allCategories); processCategories(); occupy(1, 'S1'); visualizeCategories(); occupy(3, 'S5'); visualizeCategories(); occupy(1, 'S2'); visualizeCategories(); occupy(1, 'S3'); visualizeCategories(); deoccupy(3, 'S5'); visualizeCategories(); deoccupy(1, 'S1'); visualizeCategories(); deoccupy(1, 'S3'); visualizeCategories(); deoccupy(1, 'S2'); visualizeCategories(); allCategories = { S1: ['b1'], S2: ['b1', 'b2'], S3: ['b2'] }; console.log('CATEGORIES:'); console.log(allCategories); processCategories(); occupy(1, 'S1', true); visualizeCategories(); occupy(1, 'S3', true); visualizeCategories(); 代码,但欢迎使用任何语言解决方案):

processCategories

代码说明: occupy分析可视化类别并创建数据结构,用于确定deoccupycategory = { // or "set" of items total: // NUMBER: total entries of this set occupied: // NUMBER: how many elements of this set are occupied, either directly or indirectly dueTo: // OBJECT {categoryId -> number}: how many elements of this set are indirectly occupied and due to which category. (e.g. dueTo = {S1: 1, S3: 1} means 1 occupied indirectly through S1 and 1 indirectly through S3) totalDue: 0 // NUMBER: sum of the dueTo entries }; 调用中需要占用和占用的内容。数据结构如下所示:

common

注意:

  • 类别处理创建common['S1']['S2'] === 4对象,它本质上是一个二维数组,它保存了类别有多少常见元素。 (例如occupied - totalDue
  • var atLeastThatMustOccupied = (category.occupied + commonCount) - category.total;给出了直接占用的(红色)条目。
  • 为了占用条目我使用

    dueTo

在某些情况下似乎有效,但在其他情况下则无法正常工作。

  • SELECT id, name, CASE WHEN dob2 < current_date THEN dob2 + interval '1 year' ELSE dob2 END AS birthday FROM people, make_date(extract(year from current_date)::int, extract(month from dob)::int, extract(day from dob)::int) as dob2 WHERE is_active = true ORDER BY birthday LIMIT 5; 用于取消占用条目。

在第一张图片中,代码工作正常,在此示例中代码失败: enter image description here

在最糟糕的情况下,真实世界的场景中,这些集最多可以有300个项目,最多可以有10个集合,并且算法应该足够快(希望<1s in common cpus)来确定可以挑选多少项目从所有集。此外,该算法应该能够解除占用项目,例如做相反的事情 - 从集合中删除一个项目,并确定现在可以从其他集合中选择多少项目。

假设元素只有在直接从该集合占用时才能从集合中解除占用。 (例如,如果S3 = [&#39; b1&#39;,&#39; b2&#39;,&#39; b3&#39;]并且其所有元素都间接占用,则无法调用de-occupy从S3中删除元素

0 个答案:

没有答案