01背包问题,矩阵搜索方式查找合法结果。

 注册csdn有些年头了,遇到问题也就上来搜搜,练就了一身复制粘贴的本领,但是自己从来没有贡献出来啥。一是觉得自己做的东西不够洋气,二是本身就是个低调的人。

废话不多说,这次发这文,应该算是一个01背包问题。

具体需求,对账 A=100 Bs=20,10,30,40,90 获取A在Bs中能完整匹配出A的最优组合比如 90+10=100 或者 20+10+30+40=100。

刚拿到这问题看似很简单,一顿操作之后发现还有点难度,上一个版本选择了使用全组合穷举去碰,但是,深知这么做的效率低下,现在Bs中数据为5个数字效率尚可,但是如果Bs中数字超过7个大家心算下看有多少组合,运算时间呈指数及增加。

所以就想出了当前这个方法,也拿出来跟大家分享一下,当前方式是速度优先也就说要只要匹配出第一个合法结果就返回,大家也可以改成匹配出所有结果,然后根据查询深度来返回最优结果。

大体思路

具体代码。复制来就可以用

    public class MatrixSearch
    {
        public MatrixSearch(List<MatrixItem> BaseCheckList, double? BaseCheckValue)
        {
            if (BaseCheckList.Count == 0)
            {
                throw new Exception("集合为空");
            }

            _BaseCheckList = BaseCheckList;
            _BaseCheckValue = BaseCheckValue == null ? 0 : (double)BaseCheckValue;
        }
        public List<MatrixItem> _BaseCheckList { get; private set; }
        public double _BaseCheckValue { get; private set; }
        public int Deep { get; private set; }

        public List<MatrixItem> RealPath { get; private set; } = null;

        public static List<MatrixItem> GetNoIdList(List<double?> checkList)
        {
            var re = new List<MatrixItem>();
            for (int i = 0; i < checkList.Count; i++)
            {
                re.Add(new MatrixItem() { Id = i.ToString(), Value = checkList[i] == null ? 0 : (double)checkList[i] });

            }
            return re;
        }

        public void testtes()
        {
            //BaseCheckValue = 117;
            //BaseCheckList = new List<MatrixItem>();
            //BaseCheckList.Add(new MatrixItem() { Id = "1", Value = 1 });
            //BaseCheckList.Add(new MatrixItem() { Id = "2", Value = 1 });
            //BaseCheckList.Add(new MatrixItem() { Id = "3", Value = 1 });
            //BaseCheckList.Add(new MatrixItem() { Id = "4", Value = 1 });
            //BaseCheckList.Add(new MatrixItem() { Id = "5", Value = 1 });
            //BaseCheckList.Add(new MatrixItem() { Id = "6", Value = 1 });
            //BaseCheckList.Add(new MatrixItem() { Id = "7", Value = 45 });
            //BaseCheckList.Add(new MatrixItem() { Id = "8", Value = 50 });
            //BaseCheckList.Add(new MatrixItem() { Id = "9", Value = 55 });
            //BaseCheckList.Add(new MatrixItem() { Id = "10", Value = 60 });
            //BaseCheckList.Add(new MatrixItem() { Id = "11", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "12", Value = 70 });
            //BaseCheckList.Add(new MatrixItem() { Id = "13", Value = 75 });
            //BaseCheckList.Add(new MatrixItem() { Id = "14", Value = 80 });
            //BaseCheckList.Add(new MatrixItem() { Id = "15", Value = 85 });
            //BaseCheckList.Add(new MatrixItem() { Id = "16", Value = 90 });
            //BaseCheckList.Add(new MatrixItem() { Id = "17", Value = 100 });
            //BaseCheckList.Add(new MatrixItem() { Id = "18", Value = 105 });
            //BaseCheckList.Add(new MatrixItem() { Id = "19", Value = 10 });
            //BaseCheckList.Add(new MatrixItem() { Id = "20", Value = 15 });
            //BaseCheckList.Add(new MatrixItem() { Id = "21", Value = 20 });
            //BaseCheckList.Add(new MatrixItem() { Id = "22", Value = 25 });
            //BaseCheckList.Add(new MatrixItem() { Id = "23", Value = 30 });
            //BaseCheckList.Add(new MatrixItem() { Id = "24", Value = 40 });
            //BaseCheckList.Add(new MatrixItem() { Id = "25", Value = 45 });
            //BaseCheckList.Add(new MatrixItem() { Id = "26", Value = 50 });
            //BaseCheckList.Add(new MatrixItem() { Id = "27", Value = 55 });
            //BaseCheckList.Add(new MatrixItem() { Id = "28", Value = 60 });
            //BaseCheckList.Add(new MatrixItem() { Id = "29", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "30", Value = 70 });
            //BaseCheckList.Add(new MatrixItem() { Id = "31", Value = 75 });
            //BaseCheckList.Add(new MatrixItem() { Id = "32", Value = 80 });
            //BaseCheckList.Add(new MatrixItem() { Id = "33", Value = 85 });
            //BaseCheckList.Add(new MatrixItem() { Id = "34", Value = 90 });
            //BaseCheckList.Add(new MatrixItem() { Id = "35", Value = 100 });
            //BaseCheckList.Add(new MatrixItem() { Id = "36", Value = 105 });
            //BaseCheckList.Add(new MatrixItem() { Id = "37", Value = 60 });
            //BaseCheckList.Add(new MatrixItem() { Id = "38", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "39", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "40", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "41", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "42", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "43", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "44", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "45", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "46", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "47", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "48", Value = 65 });
            //BaseCheckList.Add(new MatrixItem() { Id = "49", Value = 8 });
            //BaseCheckList.Add(new MatrixItem() { Id = "50", Value = 65 });


            //Console.WriteLine("待验证数字:{0}", _BaseCheckValue);

            Stopwatch sw = new Stopwatch();
            sw.Restart();
            var re = MatrixRun(new List<MatrixItem>(), 0);
            sw.Stop();
            //Console.WriteLine("运算实际时间:{0}", sw.ElapsedMilliseconds);

            if (re)
            {
                StringBuilder sb = new StringBuilder();

                double sumdata = 0;
                foreach (var min in RealPath)
                {
                    sb.AppendFormat("+{0}[{1}]", min.Value, min.Id);
                    sumdata = sumdata + min.Value;
                }
                sb.AppendFormat("={0}", sumdata);
                Console.WriteLine(sb.ToString().Remove(0, 1));

            }

        }


        public bool StartSearch()
        {



            //Console.WriteLine("待验证数字:{0}", _BaseCheckValue);

            Stopwatch sw = new Stopwatch();
            sw.Restart();
            var re = false;
            var sumBs = _BaseCheckList.Sum(p => p.Value);
            if (sumBs == _BaseCheckValue || _BaseCheckList.Select(p => p.Value).Contains(_BaseCheckValue))
            {

                re = true;
                RealPath = new List<MatrixItem>();
                RealPath.AddRange(_BaseCheckList);
            }
            else if (sumBs < _BaseCheckValue)
            {
                re = false;
            }
            else if (_BaseCheckList.Count(p => p.Value > _BaseCheckValue) == _BaseCheckList.Count)
            {
                re = false;
            }
            else
            {
                re = MatrixRun(new List<MatrixItem>(), 0);

            }


            sw.Stop();
            //Console.WriteLine("运算实际时间:{0}", sw.ElapsedMilliseconds);

            if (re)
            {

                //日志
                //StringBuilder sb = new StringBuilder();
                //double sumdata = 0;
                //foreach (var min in RealPath)
                //{
                //    sb.AppendFormat("+{0}[{1}]", min.Value, min.Id);
                //    sumdata = sumdata + min.Value;
                //}
                //sb.AppendFormat("={0}", sumdata);
                //Console.WriteLine(sb.ToString().Remove(0, 1));

            }
            return re;

        }


        /// <summary>
        /// 矩阵相加计算最优路径
        /// </summary>
        /// <param name="sumList"></param>
        /// <param name="deep"></param>
        /// <returns></returns>
        private bool MatrixRun(List<MatrixItem> sumList, int deep)
        {

            Deep = deep;


            var sumDoneList = new List<MatrixItem>();//本轮需要相加的结果列表
            if (deep == 0)
            {
                sumList = new List<MatrixItem>();
                foreach (var cin in _BaseCheckList)
                {
                    var additem = new MatrixItem();
                    additem.Id = cin.Id;
                    additem.Value = cin.Value;
                    sumList.Add(additem);

                }
            }

            for (int i = 0; i < sumList.Count; i++)//循环上一次穿过来结果列表跟基础列表相加
            {
                for (int n = 0; n < _BaseCheckList.Count; n++)
                {
                    var addMI = Add(sumList[i], _BaseCheckList[n], _BaseCheckValue, sumDoneList, deep);
                    if (addMI != null)
                        sumDoneList.Add(addMI);
                }
            }


            //做完一波开始判断
            if (RealPath != null)   //有结果ok
            {
                return true;
            }
            else if (sumDoneList.Count == 0)//加不出结果了就是匹配不成了
            {
                return false;
            }
            else if (sumDoneList.Count != 0 && RealPath == null)//没匹配成功并且相加结果里还有值就继续
            {
                return MatrixRun(sumDoneList, ++deep);
            }
            else
            {

                return false;
            }




        }


        private MatrixItem Add(MatrixItem A, MatrixItem B, double checkValue, List<MatrixItem> sumList, int deep)
        {
            if (deep != 0 && A.Id.Contains(B.Id))//不是第一层时候已经加过的数字不用再加 1+2 和2+1就是一个东西
            {
                return null;
            }
            else if (deep == 0 && A.Id == B.Id)//第一层自己不让加自己
            {
                return null;
            }
            else
            {
                MatrixItem re = new MatrixItem();
                re.Id = string.Format("_{0}_{1}", A.Id, B.Id);//为当前对象命名也可以当做路径来用
                re.Value = A.Value + B.Value;//+++
                if (sumList.Any(p => p.Value == re.Value))//如果即集合里已经有一样的结果的话 那么也舍去 因为依然是1+2 2+1的情况
                    return null;
                if (checkValue < re.Value)//如果结果大于要比对的数字也舍去是无意义的
                    return null;

                re.Path.Add(A.Id);//添加路径
                re.Path.Add(B.Id);

                if (checkValue == re.Value)//如果等于那就直接愉快的返回了
                {
                    RealPath = new List<MatrixItem>();
                    var reids = string.Join("_", re.Path).Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
                    RealPath = _BaseCheckList.Where(p => reids.Contains(p.Id)).ToList();


                    //Console.WriteLine("路径:{0} 值:{1}", string.Join("-", RealPath.Path), RealPath.Value);
                }


                return re;


            }

        }
    }

    public class MatrixItem
    {
        public string Id { get; set; }
        public List<string> Path { get; set; } = new List<string>();

        public double Value { get; set; }


    }

 用例:

var checklist = new List<MatrixItem>();
for (int s = 0; s < schooldata.Count(); s++)
{
    checklist.Add(new MatrixItem() { Id = schooldata[s].cedu_id, Value = schooldata[s].amount == null ? 0 : double.Parse(schooldata[s].amount) });
}

MatrixSearch ms = new MatrixSearch(checklist, double.Parse(college_s[i].amount));
var re = ms.StartSearch();

if (re)
{
ms.RealPath//成功的路径
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值