题目
下图是一个装备系统的合成图谱,箭头指向的是合成之后的装备,每合成一个装备需要消耗一些金币(标注在矩形框里面),箭头上的数字表示合成所需的材料数量。比如,要合成n个装备A,需要消耗3n个装备B、1n个装备C、4n个装备D,而且还需要消耗26n金币(装备B和装备D的合成与此类似)。
为了简单起见,下面题目的装备图谱都是一棵多叉树,而且玩家最初只拥有指定数量的叶子节点的装备,也就是图中的装备C、装备E、装备F和装备G。
注意,下面的图谱只是一个例子,作答的时候不要局限于这个图谱。
已知玩家拥有一些初级装备(叶子节点的装备)和n个金币,并且所有装备的合成都需要消耗金币,玩家需要合成尽可能多的某个装备(记为装备X),请用C#语言计算出玩家最多可以合成出多少个装备X。
为了规范输入输出,下面给出代码的基本结构,作答的时候不要修改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 materialList; //合成该物品所需的材料
}
///
/// 计算用 totalGold 金币最多可以合成的 item 装备的数量
///
/// 要合成的装备
/// 拥有的金币
/// 可合成的 item 装备的最大数量
public int Run(ItemData item, int totalGold)
{
return 0;
}
}
刚开始做这题的时候因为作答时间断断续续的,然后逻辑也断断续续的,写了一个demo就测试一下,今天下午再做测试时发现问题很大,然后做出了修改。
下面开始作答
Get题目的重点:
1.图谱只是一个例子,作答的时候不要局限于这个图谱。(说明装备和子材料的基础属性都是未知的,抽象的,其中materialList处可无限套娃)
2.作答的时候不要修改Run函数的函数原型
3.根据题目要求可知:将随意给Run()传入金币和ItemData即物品的id、当前数量、合成一个所需的金币、合成该物品所需的材料列表,返回合成后的目标装备数量。
解题逻辑:先把所有材料遍历存储,再把原有的子材料合成目标装备,然后逐个合成目标装备,每个的合成操作都是消耗金币和材料的,金币或材料不足时停止合成,输出结果。
代码实现
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleRun
{
class Program
{
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)
{
Gold = totalGold;//存储金币
Material(item);//开始遍历材料
while (SubMaterial(item) == true) ;//合成装备
return item.count;//返回结果
}
Dictionary<int, ItemData> MaterialDic = new Dictionary<int, ItemData>();//存储材料,Key为存放所需的材料ID
int Gold;//拥有的金币
/// <summary>
/// 程序入口
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
//目标装备
MaterialData materialData2 = new MaterialData { };//合成目标装备所需材料id为2的数据
MaterialData materialData3 = new MaterialData { };//合成目标装备所需材料id为3的数据
ItemData Dt = new ItemData { };//需要合成的装备
List<MaterialData> materialList = new List<MaterialData>();//目标装备的合成所需材料列表
List<MaterialData> materialList2 = new List<MaterialData>();//材料id为2的合成所需材料列表
List<MaterialData> materialList3 = new List<MaterialData>();//材料id为3的合成所需材料列表
//初始化装备的信息
Dt.id = 1;
Dt.costGold = 10;
Dt.materialList = materialList;
//合成目标装备所需的材料
materialData2.count = 2;
materialData2.item = new ItemData { };
materialData2.item.id = 2;
materialData2.item.count = 10;
materialData2.item.costGold = 6;
materialData2.item.materialList = materialList2;
materialList.Add(materialData2);//合成目标装备需要材料2
materialData3.count = 3;
materialData3.item = new ItemData { };
materialData3.item.id = 3;
materialData3.item.count = 33;
materialData3.item.costGold = 6;
materialData3.item.materialList = materialList3;
materialList.Add(materialData3);//合成目标装备需要材料3
materialList2.Add(materialData3);//合成材料2也是需要材料3
Exam exam = new Exam();
int count = exam.Run(Dt, 72);//合成装备
Console.WriteLine("您最终合成了{0}个装备!", count);
Console.ReadKey();
}
/// <summary>
/// 遍历存储所有材料
/// </summary>
public void Material(ItemData item)
{
foreach (var i in item.materialList)
{
//存储材料
MaterialDic[i.item.id] = i.item;
//当materialList不为空时,说明当前材料还有其他子材料,故继续遍历存储
if (!i.item.materialList.Any())
{
Material(i.item);//继续遍历存储
}
}
}
/// <summary>
/// 逐个合成,当金币或材料不足返回停止合成
/// </summary>
public bool SubMaterial(ItemData item)
{
//遍历合成所需的材料表
foreach (var i in item.materialList)
{
//当前材料数量少于合成所需数量时,合成材料
if (MaterialDic[i.item.id].count < i.count)
{
//判读该材料有无所需合成材料的列表
if (i.item.materialList.Any())
{
//进行多次合成,直到材料足够合成一个上级材料
for (int j = i.item.count; j < i.count; j++)
{
SubMaterial(i.item);
}
}
else
{
//当前材料不可被合成
return false;
}
//该材料拥有的数量还小于需求数量,返回
if (i.item.count < i.count)
{
return false;
}
}
}
//当前材料满足合成上级装备,消耗材料和金币
if (Gold >= item.costGold)
{
foreach (var i in item.materialList)
{
i.item.count -= i.count;
//当消耗需求表的最后一个材料时,消耗金币,上级材料的数量+1
if (i == item.materialList.Last())
{
Gold -= item.costGold;
item.count += 1;
}
}
}
else
{
//金币不足
return false;
}
return true;//合成了一个材料或装备
}
}
}
}
测试
我在初始化的代码中设
合成目标装备:需要10金币,id为2的材料2个,id为3的材料3个
合成id为2的材料需要金币6个;id为3的材料为3个
当前拥有:金币72,id为2的材料10个,id为3的材料33个
当把金币设为100时
得到的结果:id为2的材料剩余0,id为3的材料剩余0,金币剩余6.
当把金币设为233时
得到的结果:id为2的材料剩余0,id为3的材料剩余0,金币剩余139.
结果还是合成7个装备
还有对材料数量等更改的测试也没有发现bug哦,这里就不一一举例了。