c#最优解算法Google Optimization Tools
- 背景
- 发票报销,比如一个月饭贴500元。手里一把发票,怎么凑个最优解?
- 废话
- 自己写个?算了吧,40了,算法都撂下了。17年的code职涯只是ctrlC ctlvV吗?惭愧。web开发让你就是个拧螺丝的。还是网上找找吧~
- 最优组合算法(多个结果)
- 这个代码实现了,但是可能算法不够优雅。
-
/// <summary> /// 最优组合算法(多个结果) /// </summary> internal class TheMaxValue { public static void SortTest(double[] args, double argsum)//数组。和 { Array.Sort(args);//升序 Array.Reverse(args);//取反变倒叙 List<double> List2 = new List<double>(args);//整型数组转list for (int i = 0; i < List2.Count; i++) { List<double> List3 = new List<double>(); List3.Add(List2[i]); List2.RemoveAt(i); for (int j = 0; j < List2.Count; j++) { if ((double)List2[j] <= argsum - CountList(List3) - 0.5) { List3.Add(List2[j]); List2.RemoveAt(j); j = -1; } } string strArray = string.Join(",", List3); Console.WriteLine($"为每次分组的结果:{strArray}"); i = -1; } } public static double CountList(List<double> list) { double sum = 0; for (int i = 0; i < list.Count(); i++) { sum += list[i]; } return sum; } //返回结果可用结果集来接收: public static Dictionary<int, List<double>> Sort(double[] args, double argsum)//数组。和 { Dictionary<int, List<double>> List = new Dictionary<int, List<double>>(); Array.Sort(args);//升序 Array.Reverse(args);//取反变倒叙 List<double> List2 = new List<double>(args);//整型数组转list int count = 0;//List中元素键 for (int i = 0; i < List2.Count; i++) { List<double> List3 = new List<double>(); List3.Add(List2[i]); List2.RemoveAt(i); for (int j = 0; j < List2.Count; j++) { if ((double)List2[j] <= argsum - CountList(List3) ) { List3.Add(List2[j]); List2.RemoveAt(j); j = -1; } } List.Add(count++, List3); i = -1; } return List; } }
- 直接调用,可以得到多个解。由于可能手里发票少凑不到,我调了附近的数
internal class Program { static void Main(string[] args) { //调用方法: //int[] arr = { 1, 595, 600, 499, 497, 476, 5, 4, 3, 2, 1, 39, 500, 400, 455, 466, 478, 483, 35, 16, 5, 15, 6, 7, 8, 4, 7, 35, 13, 10, 2, 21, 40, 41, 33, 39, 31, 26, 11, 51, 77, 43, 36, 81, 23, 15, 72, 45, 83, 29, 55, 2, 3, 6, 9, 4, 5, 5, 6, 7, 4, 3 }; string[] temp = "1, 595, 600, 499, 497, 476, 5, 4, 3, 2, 1, 39, 500, 400, 455, 466, 478, 483, 35, 16, 5, 15, 6, 7, 8, 4, 7, 35, 13, 10, 2, 21, 40, 41, 33, 39, 31, 26, 11, 51, 77, 43, 36, 81, 23, 15, 72, 45, 83, 29, 55, 2, 3, 6, 9, 4, 5, 5, 6, 7, 4, 3".Split(','); double[] ints = new double[temp.Length];//int类型数组 for (int i = 0; i < temp.Length; i++) { ints[i] = Convert.ToInt32(temp[i]);//整数数组 } int len = Convert.ToInt32(450); int lenS = len - 10; int lenM = len + 10; while(lenS <= lenM){ GetMax(ints, lenS); lenS++; } Console.Read(); } private static void GetMax(double[] ints, double len) { Console.WriteLine(len); var sb = new StringBuilder(); Dictionary<int, List<double>> reslist = TheMaxValue.Sort(ints, len); for (int i = 0; i < reslist.Count(); i++) { string str = $"miss:{len-reslist[i].Sum()} sum:{reslist[i].Sum()}——"; for (int j = 0; j < reslist[i].Count(); j++) { str += reslist[i][j] + ","; } sb.Append(str + "\r\n"); } Console.WriteLine(sb.ToString()); Console.WriteLine(); } }
- Google Optimization Tools
- 又找到了权威的c++,应该快了。
- 看代码,很明显,这个问题就是 背包简化了。
-
using System; using System.Collections.Generic; using Google.OrTools.Algorithms; namespace ConsoleApp1 { /// <summary> /// 背包 ConsoleAppCoreOR-Tools /// https://developers.google.cn/optimization/pack/knapsack?hl=zh-cn#java_4 /// </summary> public class Knapsack { public static void MainTest() { KnapsackSolver solver = new KnapsackSolver( KnapsackSolver.KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, "KnapsackExample"); //包含项权重的矢量 //long[] values = { 360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147, 78, // 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28, 87, 73, // 78, 15, 26, 78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276, 312 }; //包含项目值的向量 //long[,] weights = { { 7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, // 42, 9, 0, 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, // 7, 29, 93, 44, 71, 3, 86, 66, 31, 65, 0, 79, 20, 65, 52, 13 } }; long[] values = { 1, 595, 600, 499, 497, 476, 5, 4, 3, 2, 1, 39, 500, 400, 455, 466, 478, 483, 35, 16, 5, 15, 6, 7, 8, 4, 7, 35, 13, 10, 2, 21, 40, 41, 33, 39, 31, 26, 11, 51, 77, 43, 36, 81, 23, 15, 72, 45, 83, 29, 55, 2, 3, 6, 9, 4, 5, 5, 6, 7, 4, 3 }; long[,] weights = { { 1, 595, 600, 499, 497, 476, 5, 4, 3, 2, 1, 39, 500, 400, 455, 466, 478, 483, 35, 16, 5, 15, 6, 7, 8, 4, 7, 35, 13, 10, 2, 21, 40, 41, 33, 39, 31, 26, 11, 51, 77, 43, 36, 81, 23, 15, 72, 45, 83, 29, 55, 2, 3, 6, 9, 4, 5, 5, 6, 7, 4, 3 } }; long[] capacities = { 650 }; solver.Init(values, weights, capacities); long computedValue = solver.Solve(); Console.WriteLine("Optimal Value = " + computedValue); int len = values.Length; var packed_items = new List<int>() ; var packed_weights = new List<long>() ; long total_weight = 0; for (int i = 0; i < len; i++) { if (solver.BestSolutionContains(i)) { packed_items.Add ( i); packed_weights.Add(weights[0, i]); total_weight += weights[0, i]; } } Console.WriteLine($"'Total weight:', {total_weight}"); Console.WriteLine($"'Packed items:', {string.Join(',', packed_items)}"); Console.WriteLine($"'Packed_weights:', {string.Join(',',packed_weights)}"); } } }