Я работал над проблемой, связанной с частным случаем задачи о рюкзаке/сумме подмножества. Проблема заключается в следующем:
У вас есть набор размеров пакетов в уменьшающихся размерах, которые случайны, например: {47, 35, 22, ...}
. У вас есть значение, которое представляет собой количество виджетов, например: #widgets = 33. Найдите наименьшее количество пакетов, которые могут составить количество виджетов для пакета. Если нет способа вернуть множество, равное количествам, верните null.
- Example 1:
- Bundle Sizes: 46, 25, 12, 4, 3
- количество: 30
- Возвращаемое значение: {46:0, 25:0, 12:2, 4:0, 3:2} (размер пакета: # пакетов)
- Example 2:
- Bundle Sizes: 46, 25, 12, 4, 3
- количество: 17
- Возвращаемое значение: {46:0, 25:0, 12:0, 4:2, 3:3}
- Example 3:
- Bundle Sizes: 46, 25, 12, 4, 3
- количество: 47
- Возвращаемое значение: {46:0, 25:1, 12:1, 4:1, 3:2}
- Example 4:
- Bundle Sizes: 46, 25, 12, 4, 3
- количество: 5
- Возвращаемое значение: ноль
Как бы решить эту проблему?
Я написал программу на C#, которая выполняет достаточно близкую работу, но сбрасывает индекс в цикле for, чтобы сбрасывать размеры пакетов, которые не будут работать с остальным набором. Опубликую источник, если потребуется, о том, как далеко он заходит.
Запрашиваемый код:
public List<int> BreakDown(List<int> bunSize, int buySize)
{
List<int> tempBunSize = bunSize.ToList();
tempBunSize.RemoveAll(e => e > buySize);
List<int> ammountNeeded = new List<int>();
int result = buySize;
for (int index = 0; index < tempBunSize.Count; index++)
{
int size = tempBunSize[index];
int tempResult = 0;
double calcResult = 0;
int addAmmount = 0;
if (index == tempBunSize.Count - 2)
{
tempResult = result % size;
if ((tempBunSize.Count > 2 || result % tempBunSize[tempBunSize.Count - 1] == 0))
{
if (result % size != 0)
{
ammountNeeded.Add(0);
tempResult = result % tempBunSize[tempBunSize.Count - 1];
if (tempResult != 0)
{
tempResult = result;
int sizeInc = 0;
while (tempResult != 0)
{
tempResult = tempResult - size;
sizeInc++;
if (tempResult < 0)
{
int decreaseOne = ammountNeeded.First();
ammountNeeded[0] = --decreaseOne;
result = result + tempBunSize.First();
if (ammountNeeded[0] <= 0)
{
tempBunSize.RemoveAt(0);
index = 0;
ammountNeeded = new List<int>();
}
ammountNeeded.Remove(0);
--index;
break;
}
if (tempResult % tempBunSize[tempBunSize.Count - 1] == 0)
{
ammountNeeded.Remove(0);
ammountNeeded.Add(sizeInc);
ammountNeeded.Add(tempResult / tempBunSize[tempBunSize.Count - 1]);
break;
}
}
if (tempResult < 0) continue;
break;
}
else
{
calcResult = result / tempBunSize[tempBunSize.Count - 1];
addAmmount = (int)Math.Floor(calcResult);
ammountNeeded.Add(addAmmount);
break;
}
}
else if (result % size == 0)
{
tempResult = result % size;
if (tempResult != 0 && result % tempBunSize[tempBunSize.Count - 1] != 0)
{
int decreaseOne = ammountNeeded.First();
ammountNeeded.Insert(0, --decreaseOne);
result = result + tempBunSize.First();
continue;
}
else
{
calcResult = result / size;
addAmmount = (int)Math.Floor(calcResult);
ammountNeeded.Add(addAmmount);
if (result % size == 0)
{
ammountNeeded.Add(0);
break;
}
calcResult = result / tempBunSize[tempBunSize.Count - 1];
addAmmount = (int)Math.Floor(calcResult);
ammountNeeded.Add(addAmmount);
break;
}
}
}
else if (tempResult % tempBunSize[tempBunSize.Count - 1] != 0)
{
tempResult = result;
int sizeInc = 0;
while (tempResult != 0)
{
tempResult = tempResult - size;
sizeInc++;
if (tempResult % tempBunSize[tempBunSize.Count - 1] == 0)
{
ammountNeeded.Add(sizeInc);
ammountNeeded.Add(tempResult / tempBunSize[tempBunSize.Count - 1]);
break;
}
}
break;
}
else if (result == 0)
{
while (ammountNeeded.Count < bunSize.Count)
{
ammountNeeded.Add(0);
}
break;
}
else
{
calcResult = result / size;
ammountNeeded.Add((int)Math.Floor(calcResult));
calcResult = tempResult / tempBunSize[tempBunSize.Count - 1];
ammountNeeded.Add((int)Math.Floor(calcResult));
break;
}
}
ammountNeeded.Add((int)Math.Floor((decimal)result / size));
result = result % size;
if (result == 0) continue;
}
if (ammountNeeded.Count < bunSize.Count)
{
ammountNeeded.Reverse(0, ammountNeeded.Count);
while (ammountNeeded.Count < bunSize.Count)
{
ammountNeeded.Add(0);
}
ammountNeeded.Reverse(0, ammountNeeded.Count);
}
if (ammountNeeded.FindLast(e => e < 0) < 0 || ammountNeeded.Sum() == 0)
return null;
return ammountNeeded;
}
}