注册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//成功的路径
}