跳跃表解决01背包问题
挺有意思的题目
看算法设计与分析有跳跃点实现,解决空间复杂度,感觉好烧脑,就实现了一下
结果
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading.Tasks;
namespace JumpPackage
{
//一个物品信息
public class Item
{
public int weight;//重量
public int val;//价值
public int id;//物品编号,名字
public Item(int w, int v, int id)
{
this.weight = w;
this.val = v;
this.id = id;
}
}
//一个背包计划
public class Plan
{
public int weight;//本计划总重量
public int val;//本计划总价值
public bool bControl;//是否受控,是则表名有同级更优计划,处理将抛弃
public List<int> items = new List<int>();//计划物品,对应最优解
public Plan()
{
weight = 0;
val = 0;
bControl = false;
}
public Plan(int w, int v)
{
weight = w;
val = v;
bControl = false;
}
}
//背包问题
public class Problem
{
public int content;//背包容量,输入获得
public List<Item> items;//所有物品,输入获得
public List<Plan> plns = new List<Plan>();//最后处理的计划集
public Problem(int cet, List<Item> its)
{
content = cet;
items = its;
}
public void Process()
{
List<Plan> right = new List<Plan>();
plns.Add(new Plan(0,0));//没有任何物品的计划,
foreach (Item it in items)
{
right = GenerateNext(plns, it);//产生下次计划
plns = UnionPlan(plns, right);//去除受控计划
}
}
public void Answer()
{
Console.WriteLine("最优方案 物品数量{0} 重量{1} 价值:{2}",
plns[plns.Count - 1].items.Count, plns[plns.Count - 1].weight, plns[plns.Count - 1].val);
Console.Write("背包信息:");
foreach (var item in plns[plns.Count - 1].items)
{
Console.Write("物品{0}:", item);
}
Console.WriteLine();
Console.WriteLine("========跳跃表信息========");
foreach (var item in plns)
{
Console.Write("({0},{1}) ", item.weight, item.val);
}
Console.WriteLine();
}
/// <summary>
/// 产生新计划
/// </summary>
/// <param name="left">旧计划</param>
/// <param name="good">新的物品</param>
/// <returns>新计划</returns>
public List<Plan> GenerateNext(List<Plan> left, Item good)
{
List < Plan > next = new List<Plan>();
foreach (var item in left)
{
if (item.weight + good.weight <= content)//不超重则录入
{
Plan temp = new Plan(item.weight + good.weight, item.val + good.val);
temp.items.AddRange(item.items);
temp.items.Add(good.id);
next.Add(temp);
}
}
return next;
}
/// <summary>
/// 合并计划
/// </summary>
/// <param name="left">旧计划集</param>
/// <param name="right">新计划集</param>
/// <returns></returns>
public List<Plan> UnionPlan(List<Plan> left, List<Plan> right)
{
List<Plan> plans = new List<Plan>();
foreach (var lItem in left)
{
foreach (var rItem in right)
{
if (lItem.weight <= rItem.weight && lItem.val > rItem.val)//旧计划和新计划比较 轻或者一样重反而价值高,则标记新计划为受控计划
{
rItem.bControl = true;
}
if (rItem.weight <= lItem.weight && rItem.val > lItem.val)//新计划和旧计划比较 轻或者一样重反而价值高,则标记旧计划为受控计划
{
lItem.bControl = true;
}
}
}
foreach (var lItem in left)
{
if (!lItem.bControl)
{
plans.Add(lItem);
}
}
foreach (var rItem in right)
{
if (!rItem.bControl)
{
plans.Add(rItem);
}
}
plans.Sort((l, r) => {
return l.weight < r.weight ? -1 : 1;
});
return plans;
}
}
internal class Program
{
public static bool IsContinue()
{
Console.Write("是否继续(N/Y)?: ");
string val = Console.ReadLine();
while (val != "Y" && val != "y" && val != "N" && val != "n")
{
Console.Write("是否继续(N/Y)?: ");
val = Console.ReadLine();
}
return val == "Y" || val == "y";
}
public static int ReadContent()
{
Console.Write("背包容量(正整数): ");
string val = Console.ReadLine();
int num;
while (!int.TryParse(val, out num) || num <= 0)
{
Console.Write("输入错误,重新输入背包容量(正整数): ");
val = Console.ReadLine();
}
return num;
}
public static int ReadCount()
{
Console.Write("物品数量(正整数): ");
string val = Console.ReadLine();
int num;
while (!int.TryParse(val, out num) || num <= 0)
{
Console.Write("输入错误,重新输入物品数量(正整数): ");
val = Console.ReadLine();
}
return num;
}
public static int ReadWeight(int idx)
{
Console.Write("物品{0}重量(正整数): ", idx);
string val = Console.ReadLine();
int num;
while (!int.TryParse(val, out num) || num <= 0)
{
Console.Write("输入错误,重新输入物品{0}重量(正整数): ", idx);
val = Console.ReadLine();
}
return num;
}
public static int ReadValue(int idx)
{
Console.Write("物品{0}价值(正整数): ", idx);
string val = Console.ReadLine();
int num;
while (!int.TryParse(val, out num) || num <= 0)
{
Console.Write("输入错误,重新输入物品{0}价值(正整数): ", idx);
val = Console.ReadLine();
}
return num;
}
static void Main(string[] args)
{
do
{
List<Item> items = new List<Item>();
int content = ReadContent();
int cnt = ReadCount();
for (int idx = 0; idx < cnt; idx++)
{
items.Add(new Item(ReadWeight(idx+1), ReadValue(idx+1), idx+1));
}
Problem problem = new Problem(content, items);
problem.Process();
problem.Answer();
} while (IsContinue());
}
}
}
程序和代码已上传,可以下载直接test
程序和代码
参考
主要是看b站张老师的课程
跳跃点 背包问题