装备合成求最大可合成数量算法题

该数据结构原型:(不允许修改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());
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_xian_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值