C# 一个类似于背包问题的规划问题

C# 一个类似于背包问题的规划问题,c#,knapsack-problem,C#,Knapsack Problem,我曾在一些stackexchange网站上询问过这一问题,他们告诉我,我应该在这里询问,并提供代码,因此: 整个问题类似于背包问题,但得到了扩展 有一个背包,上面有: 重量 耐久性 最大进度 最高质量 有一些项目。每个项目都有: 重量, 耐久性损失或增益, 有助于进步的价值观, 有助于提高质量的价值 还有一些添加“buff”的项目: 增加有助于背包进步和/或质量的价值 对于接下来的n项 减少接下来n个项目的耐久性损失 挑选下n件物品后增加耐用性 n取决于buff 背包从重量、耐久性、0进

我曾在一些stackexchange网站上询问过这一问题,他们告诉我,我应该在这里询问,并提供代码,因此:

整个问题类似于背包问题,但得到了扩展

有一个背包,上面有:

  • 重量

  • 耐久性

  • 最大进度

  • 最高质量

有一些项目。每个项目都有: 重量, 耐久性损失或增益, 有助于进步的价值观, 有助于提高质量的价值

还有一些添加“buff”的项目:

  • 增加有助于背包进步和/或质量的价值 对于接下来的n项

  • 减少接下来n个项目的耐久性损失

  • 挑选下n件物品后增加耐用性

  • n取决于buff

背包从重量、耐久性、0进度、0质量开始。相同的物品可以拾取任意次数

拣选物品时:

  • 背包增加重量

  • 背包获得进步

  • 背包获得质量

  • 背包失去或获得耐久性

相同的物品可以拾取任意次数

如果出现以下情况,您将停止拾取项目: 背包耐久性达到0, 背包进度达到最大进度, 由于背包的重量,它不能装任何物品

目标是以最少的物品和重量达到最大质量和最大进度(如果你达到最大质量和最大进度,就意味着你已经解决了问题)

大约有20件物品,暴力无法使用

提供的代码:

int maxWeight = 10;
int durability = 60;
int maxProgress = 100;
int maxQuality = 100;

int[] itemWeights =     new[] { 1,  1, 2,  3,   1,  1  };
int[] itemDurability =  new[] { 10, 0, 20, -15, 10, 10 };
int[] itemProgress =    new[] { 20, 0, 40, 0,   0,  0  };
int[] itemQuality =     new[] { 0,  0, 25, 0,   0,  0  };
int[] buffs =           new[] { 0,  1, 0,  0,   2,  3  };

//buff 1: for 4 next items after picking increase knapsack durability by 5
//buff 2: for 2 next items after picking increase progress gain by 50%
//buff 2: for 2 next items after picking increase quality gain by 50%
这只是一个简单的示例代码。实际项目包括20多个动作,进度和质量取决于其他变量,整个项目相当大,可能会使事情变得复杂。但是,如果您需要完整的源代码,可以提供

我所尝试的: 使用遗传算法来找到最优化的解决方案,这是可行的,但我想要一个数学解决方案。 使用动态规划,首先解决质量问题,然后继续进行。添加“buff”的物品会让事情变得复杂,因为它们没有实际价值

来自实际项目的暴力尝试:

private void SolveForCurrentItems(Items[] availableItems, Items[] items)
        {
            Knapsack.RemoveItems();
            Knapsack.AddItems(items);
            var currentItems = Knapsack.GetItems();
            //Knapsack.GetItems() returns items that are used
            //if picking is no longer possible, last item is not included
            if (currentItems.Length == items.Length)
            {
                for (int i = 0; i < availableItems.Length; i++)
                {
                    var newItems = new Item[currentItems.Length + 1];
                    currentItems .CopyTo(newItems , 0);
                    newItems [newItems .Length - 1] = availableItems[i];
                    SolveForCurrentItems(availableItems, newItems);
                }
            }
        }
增益等级:

public enum BuffType
{
    DurabilityRestoration,
    DurabilityModifier,
    Progress,
    Quality
}

public class Buff
{
    public int CurrentStack;
    public bool NeedsRemove { get; set; }

    public BuffType BuffType { get; private set; }
    public Buff(BuffType buffType)
    {
        BuffType = buffType;
    }

    public void Step(Knapsack knapsack)
    {
        CurrentStack--;
        if (CurrentStack == 0)
            NeedsRemove = true;
    }

}
如何使用它的示例:

Knapsack knapsack = new Knapsack { MaxWeight = 100, Durability = 60, MaxProgress = 100, MaxQuality = 100 };

        Item[] items = new Item[]
        {
            new Item {Weight = 1, Durability = 10, Progress = 20, Quality = 0, HasBuff = false },
            new Item {Weight = 1, Durability = 0, Progress = 0, Quality = 0, HasBuff = true, Buff = new Buff(BuffType.DurabilityRestoration) },
            new Item {Weight = 4, Durability = 15, Progress = 5, Quality = 25, HasBuff = false },
            new Item {Weight = 3, Durability = -15, Progress = 0, Quality = 0, HasBuff = false },
            new Item {Weight = 1, Durability = 10, Progress = 0, Quality = 0, HasBuff = true, Buff = new Buff(BuffType.Progress) },
            new Item {Weight = 1, Durability = 10, Progress = 0, Quality = 0, HasBuff = true, Buff = new Buff(BuffType.Quality) },
        };

        knapsack.CurrentItems.Add(items[4]);
        knapsack.CurrentItems.Add(items[1]);
        knapsack.CurrentItems.Add(items[5]);
        knapsack.CurrentItems.Add(items[2]);
        knapsack.CurrentItems.Add(items[2]);
        knapsack.CurrentItems.Add(items[3]);
        knapsack.CurrentItems.Add(items[2]);
        knapsack.CurrentItems.Add(items[2]);
        knapsack.CurrentItems.Add(items[1]);
        knapsack.CurrentItems.Add(items[3]);
        knapsack.CurrentItems.Add(items[3]);
        knapsack.CurrentItems.Add(items[4]);
        knapsack.CurrentItems.Add(items[0]);
        knapsack.CurrentItems.Add(items[0]);
        knapsack.CurrentItems.Add(items[4]);
        knapsack.CurrentItems.Add(items[0]);
        knapsack.ExecuteItems();

我想要的是一个以最佳方式解决问题的算法。

您已将问题标记为C,因此我建议您使用它的强大功能。 因此,与其使用单独的项目属性列表,不如使用具有这些属性的项目类,例如

interface IItem
{
  int Weight{get;set;}
  int Durability {get;set;}
  int Progress {get;set;}
  int Quality {get;set;}
  int Buff {get;set;}
}

class Item1 : IItem
{
  ...
}

class Item2 : IItem
{
  ...
}

…
然后你的
背包
类可以有一个
IItem
类的集合,它是内容

然后,如果您有一个所有基于
IItem
的唯一类的完整列表,您可以根据您感兴趣的属性对它们进行排序,并根据其标准(例如重量可能太高)选择可以放入
背包中的类,因此您可以选择重量较低的
IItem


已编辑

好吧,你最近的帖子让我原来的帖子过时了,所以有人投了反对票

尽管如此,我认为您想要的是根据您已有的标准在代码中执行某种Venn图逻辑

让我解释一下

您的目标是以最少的项目数量达到最高质量和进度,因此请按质量(最高优先)对所有项目进行排序,并不断将此排序列表中的实例添加到质量列表中,直到您达到尽可能接近最大的质量。如果当前实例不适合,请转到列表中的下一个实例并检查是否适合

对每个项目属性执行相同的过程

然后,您可以确定列表的相交位置,结果输出将接近您的最佳项目选择


我有一个明显的印象,您可能希望每个项目类型都是唯一的类,并且它们都实现相同的接口,或者它们都有一个指示其类型的属性,如果你能确定最后选择了哪一个就好了。

你已经将问题标记为C,因此我建议你使用它的威力。 因此,与其使用单独的项目属性列表,不如使用具有这些属性的项目类,例如

interface IItem
{
  int Weight{get;set;}
  int Durability {get;set;}
  int Progress {get;set;}
  int Quality {get;set;}
  int Buff {get;set;}
}

class Item1 : IItem
{
  ...
}

class Item2 : IItem
{
  ...
}

…
然后你的
背包
类可以有一个
IItem
类的集合,它是内容

然后,如果您有一个所有基于
IItem
的唯一类的完整列表,您可以根据您感兴趣的属性对它们进行排序,并根据其标准(例如重量可能太高)选择可以放入
背包中的类,因此您可以选择重量较低的
IItem


已编辑

好吧,你最近的帖子让我原来的帖子过时了,所以有人投了反对票

尽管如此,我认为您想要的是根据您已有的标准在代码中执行某种Venn图逻辑

让我解释一下

您的目标是以最少的项目数量达到最高质量和进度,因此请按质量(最高优先)对所有项目进行排序,并不断将此排序列表中的实例添加到质量列表中,直到您达到尽可能接近最大的质量。如果当前实例不适合,请转到列表中的下一个实例并检查是否适合

对每个项目属性执行相同的过程

然后,您可以确定列表的相交位置,结果输出将接近您的最佳项目选择

我有一个明显的印象,您可能希望您的每个项目类型都是一个唯一的类,并且它们都实现相同的接口,或者它们都有一个指示其类型的属性,如果只是为了让您能够确定您在最后选择了哪些。

请提供
interface IItem
{
  int Weight{get;set;}
  int Durability {get;set;}
  int Progress {get;set;}
  int Quality {get;set;}
  int Buff {get;set;}
}

class Item1 : IItem
{
  ...
}

class Item2 : IItem
{
  ...
}

…