我正在尝试使用动态编程来解决背包问题的变化:
所以我所拥有的是具有尺寸的正方形场:N * N(像棋盘一样)。在每个广场上我都有一些价值观。我能做的是在方块上添加一个(+1)或删除一个(-1)。有一个特殊的规则,即如果有相邻的正方形(具有共同的正方形 - 正方形不对数的正方形),其值等于正方形的新值,则设置所有这些相邻正方形的值为零
目标是尽可能减少所有方格的总价值。
例如,如果我有一个矩阵3x3代表一个3 * 3方格的字段,那么我们可以这样:
int[3,3] field = { 1, 2, 3, 5, 1, 6, 7, 3, 9 }
现在如果我减少一个元素[0,1]的值为2,那么所有元素[0,0] [0,1]和[1,1]都会将它们的值设置为0 。
所以基本上我到目前为止所做的就是对每个方格的每个动作进行评级,并采取一些深度的动作(意味着如果一个动作在一个方格上重复多次,我计算了评级)并保持这些评级在四维数组ratings[action, depth, row, col]
中。
评级表示平方的总值将减少的数量。
我想要的是找到最佳的动作序列,从动画中删除尽可能多的值。这必须在预定义数量的动作中发生(或者有定义的转弯数,我每回合只能做一次动作)。并且最后说了很明显,我必须从正方形的等级中找出深度子集的哪个组合将给出最高的总评级。
首先,我认为这可以通过子集求和问题来完成,然后根据其评级对收到的项目列表进行排序,但之后我意识到这可以通过背包问题实现,除了评级是相互依赖的这就是我的问题所在。例如,如果有正方形改变其值,则其相邻正方形可能会自动更改其评级。我可以写一个方法来检查广场的邻居是否会在行动后改变他们的评级,但这不是让我烦恼的事。令我担心的是如何通过改变值(方块的等级)来实现背包问题?
总结我到目前为止的情况:
对我来说,主要的问题是背包中放置的物品的价值会根据保留的物品而改变。
我必须承认我没有从头开始编写我的背包算法,而是我使用已经编写的算法并根据我的需要对其进行了转换。我从这里得到算法:http://sriwantha.blogspot.com/2011/07/knapsack-problem-in-c.html
这是我的代码:
//Knapsack problem:
//class for the items in the knapsack
public class Item
{
public int row;
public int col;
public int action;
public int depth;
public int rating;
public Item(int row, int col, int action, int depth, int rating)
{
this.row = row;
this.col = col;
this.action = action;
this.depth = depth;
this.rating = rating;
}
public override string ToString()
{
return "row,col,action=" + row + "," + col + "," + action + ", depth=" + depth + ", rating=" + rating;
}
}
class KnapSackProblem
{
public static List<Item> FindItemsToPack(List<Item> items, int depthCapacity, out int totalRatingValue)
{
int[,] ratings = new int[items.Count + 1, depthCapacity + 1];
bool[,] keep = new bool[items.Count + 1, depthCapacity + 1];
for (int i = 1; i <= items.Count; i++)
{
Item currentItem = items[i - 1];
for (int depth = 1; depth <= depthCapacity; depth++)
{
if (depth >= currentItem.depth)
{
int remainingDepth = depth - currentItem.depth;
int remainingDepthRating = 0;
if (remainingDepth > 0)
{
remainingDepthRating = ratings[i - 1, remainingDepth];
}
int currentItemTotalRating = currentItem.rating + remainingDepthRating;
if (currentItemTotalRating > ratings[i - 1, depth])
{
keep[i, depth] = true;
ratings[i, depth] = currentItemTotalRating;
}
else
{
keep[i, depth] = false;
ratings[i, depth] = ratings[i - 1, depth];
}
}
}
}
List<Item> itemsToBePacked = new List<Item>();
int remainDepth = depthCapacity;
int item = items.Count;
while (item > 0)
{
bool toBePacked = keep[item, remainDepth];
if (toBePacked)
{
itemsToBePacked.Add(items[item - 1]);
remainDepth = remainDepth - items[item - 1].depth;
}
item--;
}
totalRatingValue = ratings[items.Count, depthCapacity];
return itemsToBePacked;
}
}
从另一种方法我称之为Knapsack算法:
List<Item> actionsToDo = new List<Item>();
Item newItemTake;
Item newItemAdd;
for (int depth = 0; depth < maxDepth; depth++)
{
for (int row = 0; row < dimension; row++)
{
for (int col = 0; col < dimension; col++)
{
if (ratings[Take, depth, row, col] >= 0)
{
newItemTake = new Item(row, col, Take, depth + 1, ratings[Take, depth, row, col]);
actionsToDo.Add(newItemTake);
}
if (ratings[Add, depth, row, col] >= 0)
{
newItemAdd = new Item(row, col, Add, depth + 1, ratings[Add, depth, row, col]);
actionsToDo.Add(newItemAdd);
}
}
}
}
int totalRating = 0;
List<Item> itemsToBePacked = KnapSackProblem.FindItemsToPack(actionsToDo, maxDepth, out totalRating);
foreach (var item in itemsToBePacked)
{
Console.WriteLine(item);
}
Console.WriteLine(totalRating);