ReducableMatrix.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using System.Text;
  4. namespace TravMerchant
  5. {
  6. public class ReducableMatrix
  7. {
  8. private int?[,] matrix;
  9. private SortedSet<int> rowReduces = new SortedSet<int>();
  10. private SortedSet<int> columnReduces = new SortedSet<int>();
  11. private List<(int, int)> path = new List<(int, int)>();
  12. public ReducableMatrix(int?[,] matrix)
  13. {
  14. //Конструктор, клонирующий матрицу, для того, чтобы не затрагивать исходную по ходу программы
  15. this.matrix = (int?[,])matrix.Clone();
  16. }
  17. // Клонирующий конструктор
  18. public ReducableMatrix(ReducableMatrix matrix)
  19. {
  20. this.matrix = (int?[,])matrix.matrix.Clone();
  21. foreach (int reduce in matrix.rowReduces)
  22. rowReduces.Add(reduce);
  23. foreach (int reduce in matrix.columnReduces)
  24. columnReduces.Add(reduce);
  25. path.AddRange(matrix.path);
  26. }
  27. private ReducableMatrix(ReducableMatrix matrix, int row, int column) : this(matrix)
  28. {
  29. this.matrix[column, row] = null;
  30. rowReduces.Add(row);
  31. columnReduces.Add(column);
  32. path.Add((row, column));
  33. }
  34. //Доступ по локал координатам
  35. public int? this[int i, int j]
  36. {
  37. get
  38. {
  39. var coords = Unreduce(i, j);
  40. return matrix[coords.Item1, coords.Item2];
  41. }
  42. set
  43. {
  44. var coords = Unreduce(i, j);
  45. matrix[coords.Item1, coords.Item2] = value;
  46. }
  47. }
  48. public int GetLength(int dimension) => matrix.GetLength(dimension) - rowReduces.Count;
  49. //возврат копии матрицы без строки и ряда
  50. public ReducableMatrix Reduce(int row, int column)
  51. {
  52. var p = Unreduce(row, column);
  53. return new ReducableMatrix(this, p.Item1, p.Item2);
  54. }
  55. //перевод локал в глобал
  56. private (int, int) Unreduce(int row, int column)
  57. {
  58. foreach (var reduce in rowReduces)
  59. {
  60. if (row >= reduce)
  61. row++;
  62. }
  63. foreach (var reduce in columnReduces)
  64. {
  65. if (column >= reduce)
  66. column++;
  67. }
  68. return (row, column);
  69. }
  70. public int[] RowMinimums()
  71. {
  72. int[] minimums = new int[GetLength(0)];
  73. for (int i = 0; i < GetLength(0); i++)
  74. {
  75. minimums[i] = int.MaxValue;
  76. for (int j = 0; j < GetLength(1); j++)
  77. {
  78. if (this[i, j] == null)
  79. continue;
  80. if (minimums[i] > this[i, j])
  81. minimums[i] = (int)this[i, j];
  82. }
  83. }
  84. return minimums;
  85. }
  86. public int[] ColMinimums()
  87. {
  88. int[] minimums = new int[GetLength(1)];
  89. for (int j = 0; j < GetLength(1); j++)
  90. {
  91. minimums[j] = int.MaxValue;
  92. for (int i = 0; i < GetLength(0); i++)
  93. {
  94. if (this[i, j] == null)
  95. continue;
  96. if (minimums[j] > this[i, j])
  97. minimums[j] = (int)this[i, j];
  98. }
  99. }
  100. return minimums;
  101. }
  102. //Посчитать нижнюю границу + редукция строк и столбцов.
  103. public int? CalculateLowerBound(int? lastSum)
  104. {
  105. int[] rowMinimums = RowMinimums();
  106. for (int i = 0; i < GetLength(0); i++)
  107. {
  108. for (int j = 0; j < GetLength(1); j++)
  109. {
  110. if (this[i, j] != null)
  111. this[i, j] -= rowMinimums[i];
  112. }
  113. }
  114. int[] colMinimums = ColMinimums();
  115. for (int i = 0; i < GetLength(0); i++)
  116. {
  117. for (int j = 0; j < GetLength(1); j++)
  118. {
  119. if (this[i, j] != null)
  120. this[i, j] -= colMinimums[j];
  121. }
  122. }
  123. return rowMinimums.Sum() + colMinimums.Sum() + lastSum;
  124. }
  125. public int?[,] CalculateWeights()
  126. {
  127. int?[,] weights = new int?[GetLength(0), GetLength(1)];
  128. for (int i = 0; i < GetLength(0); i++)
  129. {
  130. for (int j = 0; j < GetLength(1); j++)
  131. {
  132. if (this[i, j] == 0)
  133. {
  134. int? min = null;
  135. for (int k = 0; k < GetLength(0); k++)
  136. {
  137. if (this[i, j] == null || j == k)
  138. continue;
  139. if (min == null || this[i, k] < min)
  140. min = this[i, k];
  141. }
  142. weights[i, j] = min;
  143. min = null;
  144. for (int k = 0; k < GetLength(1); k++)
  145. {
  146. if (this[i, j] == null || i == k)
  147. continue;
  148. if (min == null || this[k, j] < min)
  149. min = this[k, j];
  150. }
  151. weights[i, j] += min;
  152. }
  153. else
  154. weights[i, j] = 0;
  155. }
  156. }
  157. return weights;
  158. }
  159. public (int, int) FindMaxWeightPoint(int?[,] weights)
  160. {
  161. var point = (0, 0);
  162. int max = 0;
  163. for (int i = 0; i < weights.GetLength(0); i++)
  164. {
  165. for (int j = 0; j < weights.GetLength(1); j++)
  166. {
  167. if (weights[i, j] == null)
  168. return (i, j);
  169. if (weights[i, j] > max)
  170. {
  171. max = (int)weights[i, j];
  172. point = (i, j);
  173. }
  174. }
  175. }
  176. return point;
  177. }
  178. public List<(int, int)> GetPath()
  179. {
  180. return new List<(int, int)>(path);
  181. }
  182. public override string ToString()
  183. {
  184. StringBuilder sb = new StringBuilder();
  185. for (int i = 0; i < GetLength(0); i++)
  186. {
  187. for (int j = 0; j < GetLength(1); j++)
  188. {
  189. if (this[i, j] == null)
  190. sb.Append("M ");
  191. else
  192. sb.Append(string.Format("{0,-3}", this[i, j]));
  193. }
  194. sb.AppendLine();
  195. }
  196. return sb.ToString();
  197. }
  198. }
  199. }