该数据结构原型:(不允许修改Run函数)
public class Exam
{
public class MaterialData
{
public ItemData item; //合成所需的物品
public int count; //合成所需的该物品的数量
}
public class ItemData
{
public int id; //物品 ID
public int count; //当前拥有的物品数量
public int costGold; //合成该物品所需的金币
public List<MaterialData> materialList; //合成该物品所需的材料
}
/// <summary>
/// 计算用 totalGold 金币最多可以合成的 item 装备的数量
/// </summary>
/// <param name="item">要合成的装备</param>
/// <param name="totalGold">拥有的金币</param>
/// <returns>可合成的 item 装备的最大数量</returns>
public int Run(ItemData item, int totalGold)
{
return 0;
}
}
以下我提供2种解题代码:(该问题主要还是要对树作遍历)
1.暴力穷举法,穷举合成过程得出结果,时间代价较大,数据量大时不可取
public class Exam
{
//所需材料类
public class MaterialData
{
public ItemData item; //合成所需的物品
public int count; //合成所需的该物品的数量
}
//合成目标类
public class ItemData
{
public int id; //物品 ID
public int count; //当前拥有的物品数量
public int costGold; //合成该物品所需的金币
public List<MaterialData> materialList; //合成该物品所需的材料
}
/// <summary>
/// 将需要的物品合成好
/// </summary>
/// <param name="item">要合成的装备</param>
/// <param name="totalGold">拥有的金币</param>
/// <param name="itemMax">最大合成数量</param>
public void Compound(ItemData item, ref int totalGold, ref int itemMax)
{
if (item.materialList != null)
{
foreach (var material in item.materialList)//遍历每种所需要的材料
{
Compound(material.item, ref totalGold, ref itemMax);//递归到叶子结点
//合成物品
if (totalGold >= item.costGold && material.item.count >= material.count)
{
material.item.count -= material.count;//就算没合成成功,这步减法也不会影响计算结果
}
else//当部分材料不够时或者金币不足,合成失败
{
return;
}
}
//合成成功
totalGold -= item.costGold;
item.count++;
if (item.id == 1) itemMax++;
}
return;
}
/// <summary>
/// 计算用 totalGold 金币最多可以合成的 item 装备的数量
/// </summary>
/// <param name="item">要合成的装备</param>
/// <param name="totalGold">拥有的金币</param>
/// <returns>可合成的 item 装备的最大数量</returns>
public int Run(ItemData item, int totalGold)
{
if (item.costGold > totalGold)
{
return 0;
}
int itemMax = 0;//可合成的 item 装备的最大数量
while (totalGold >= item.costGold)
{
int tempGoldByStop = totalGold;
//把所需物品合成出来
Compound(item,ref totalGold, ref itemMax);
if (totalGold == tempGoldByStop) break;//退出无效循环
}
return itemMax;
}
2.枚举优化算法,①先按金币代价求出当前拥有的金币最多可以合成的目标装备数量
②再求出材料代价,计算出①可以合成的目标装备数量 中分别需要的每个叶子结点的count数量,最后根据当前每个叶子结点拥有的item.count数量,求出真正的可以合成的目标装备数量
public class Exam
{
//所需材料类
public class MaterialData
{
public ItemData item; //合成所需的物品
public int count; //合成所需的该物品的数量
}
//合成目标类
public class ItemData
{
public int id; //物品 ID
public int count; //当前拥有的物品数量
public int costGold; //合成该物品所需的金币
public List<MaterialData> materialList; //合成该物品所需的材料
}
/// <summary>
/// 计算用 totalGold 金币最多可以合成的 item 装备的数量
/// </summary>
/// <param name="item">要合成的装备</param>
/// <param name="totalGold">拥有的金币</param>
/// <returns>可合成的 item 装备的最大数量</returns>
public int Run(ItemData item, int totalGold)
{
int maxCount = 0;
List<MaterialData> leaf = new List<MaterialData>();
List<int> MaxCounts = new List<int>();
List<int> singleNeedGolds = new List<int>();
if (item.costGold > totalGold) //肯定一件都合成不了
{
return 0;
}
int singleNeedGold = item.costGold;//合成一个目标装备所需要的金币
maxCount = MaxCountByGold(item, totalGold, singleNeedGold, singleNeedGolds);//只从金币角度考虑的可合成数
//再从材料角度考虑
leaf = MaxCountByGoldAndMaterial(item.materialList, leaf);
//计算最大可合成装备数
foreach (var raw in leaf)
{
MaxCounts = new List<int>();
int need = raw.count * maxCount;//叶子结点的需要数量
maxCount = need > raw.item.count ? maxCount - (need - raw.item.count) / raw.count -
Convert.ToInt32(maxCount - (need - raw.item.count) % raw.count != 0) : maxCount;
MaxCounts.Add(maxCount);
}
maxCount = MaxCounts.Min();
return maxCount;
}
/// <summary>
/// 计算只考虑金币成本时最多可以合成的 item 装备的数量
/// </summary>
/// <param name="item">要合成的装备</param>
/// <param name="totalGold">拥有的金币</param>
/// <param name="singleNeedGold">合成一个目标装备所需要的金币</param>
/// <returns>可合成的 item 装备的最大数量</returns>
public int MaxCountByGold(ItemData item, int totalGold, int singleNeedGold, List<int> singleNeedGolds)
{
if (item.materialList != null)
{
foreach (MaterialData material in item.materialList)
{
if (material.item.costGold != 0)
{
singleNeedGold += material.item.costGold * material.count;
singleNeedGolds.Add(singleNeedGold);
MaxCountByGold(material.item, totalGold, singleNeedGold, singleNeedGolds);
}
}
}
if(singleNeedGolds.Count != 0)
{
singleNeedGold = singleNeedGolds.Max();
}
return singleNeedGold != 0 ? totalGold / singleNeedGold : int.MaxValue;
}
/// <summary>
/// 计算从金币成本计算出最多合成时,需要的原材料数
/// </summary>
/// <param name="item">要合成的装备</param>
/// <param name="maxCount">只考虑金币可合成的最大数量</param>
/// <param name="leaf">需要的原材料数列表</param>
public List<MaterialData> MaxCountByGoldAndMaterial(List<MaterialData> materialList, List<MaterialData> leaf)
{
foreach (MaterialData material in materialList)
{
if (material.item.materialList != null)
{
foreach (MaterialData materialNext in material.item.materialList)
{
materialNext.count *= material.count;
if (materialNext.item.materialList == null)
{
leaf.Add(materialNext);
}
}
MaxCountByGoldAndMaterial(material.item.materialList, leaf);
}
else
{
if (!leaf.Contains(material))
{
leaf.Add(material);
}
}
}
return leaf;
}
以下提供main函数和一些测试数据:
static void Main(string[] args)
{
//text
ItemData A = new ItemData();
ItemData b = new ItemData();
ItemData c = new ItemData();
ItemData e = new ItemData();
ItemData f = new ItemData();
ItemData g = new ItemData();
ItemData h = new ItemData();
MaterialData B = new MaterialData();
MaterialData C = new MaterialData();
MaterialData E = new MaterialData();
MaterialData F = new MaterialData();
MaterialData G = new MaterialData();
MaterialData H = new MaterialData();
A.id = 1;
A.count = 0;
A.costGold = 26;
B.item = b;
B.item.id = 2;
B.item.count = 0;
B.item.costGold = 53;
B.count = 3;
C.item = c;
C.item.id = 3;
C.item.count = 10;
C.count = 1;
E.item = e;
E.item.id = 4;
E.item.count = 100;
E.count = 1;
F.item = f;
F.item.id = 5;
F.item.count = 100;
F.item.costGold = 10;
F.count = 5;
G.item = g;
G.item.id = 6;
G.item.count = 100;
G.count = 2;
H.item = h;
H.item.id = 7;
H.item.count = 100;
H.count = 3;
List<MaterialData> AmaterialList = new List<MaterialData>();
List<MaterialData> BmaterialList = new List<MaterialData>();
List<MaterialData> FmaterialList = new List<MaterialData>();
A.materialList = AmaterialList;
B.item.materialList = BmaterialList;
F.item.materialList = FmaterialList;
A.materialList.Add(B);
A.materialList.Add(C);
B.item.materialList.Add(E);
B.item.materialList.Add(F);
F.item.materialList.Add(G);
F.item.materialList.Add(H);
System.DateTime dateTime1 = new System.DateTime();
System.DateTime dateTime2 = new System.DateTime();
Exam exam = new Exam();
dateTime1 = System.DateTime.Now;
int maxCount = exam.Run(A, 1000);
//int maxCount = exam.MaxCountByGold(A, 1000, 26);//测试只按金币计算的函数
dateTime2 = System.DateTime.Now;
Console.WriteLine("最多可以合成的 item 装备的数量:");
Console.WriteLine(maxCount);
Console.WriteLine("函数执行时间:" + (dateTime2 - dateTime1).ToString());
}