Where is the flaw in my algorithm for consolidating gold mines?

后端 未结 2 636
栀梦
栀梦 2021-01-25 10:44

The setup is that, given a list of N objects like

class Mine
{
    public int Distance { get; set; } // from river
    public int Gold { get; set;          


        
相关标签:
2条回答
  • 2021-01-25 10:58

    The other answer does point out a flaw in the implementation, but it fails to mention that in your code, you aren't actually changing the Gold values in the remaining Mine objects. So even if you did re-sort the data, it wouldn't help.

    Furthermore, at each iteration all you really care about is the minimum value. Sorting the entire list of data is overkill. You can just scan it once to find the minimum-valued item.

    You also don't really need the separate array of flags. Just maintain your move objects in a list, and after choosing a move, remove the move objects that include the Mine you would otherwise have flagged as no longer valid.

    Here is a version of your algorithm that incorporates the above feedback:

        static void Main(String[] args)
        {
            string input =
    @"3 1
    11 3
    12 2
    13 1";
            StringReader reader = new StringReader(input);
    
            // helper function for reading lines
            Func<string, int[]> LineToIntArray = (line) => Array.ConvertAll(line.Split(' '), Int32.Parse);
    
            int[] line1 = LineToIntArray(reader.ReadLine());
            int N = line1[0], // # of mines
                K = line1[1]; // # of pickup locations
    
            // Populate mine info
            List<Mine> mines = new List<Mine>();
            for (int i = 0; i < N; ++i)
            {
                int[] line = LineToIntArray(reader.ReadLine());
                mines.Add(new Mine() { Distance = line[0], Gold = line[1] });
            }
    
            // helper function for cost of a move
            Func<Tuple<Mine, Mine>, int> MoveCost = (tuple) =>
                Math.Abs(tuple.Item1.Distance - tuple.Item2.Distance) * tuple.Item1.Gold;
    
            // all move combinations
            var moves = (from m1 in mines
                        from m2 in mines
                        where !m1.Equals(m2)
                        select Tuple.Create(m1, m2)).ToList();
    
            int sum = 0, // running total of move costs
                unconsolidatedCount = N;
            while (moves.Count > 0 && unconsolidatedCount != K)
            {
                var move = moves.Aggregate((a, m) => MoveCost(a) < MoveCost(m) ? a : m);
    
                sum += MoveCost(move); // add this consolidation to the total cost
                move.Item2.Gold += move.Item1.Gold;
                moves.RemoveAll(m => m.Item1 == move.Item1 || m.Item2 == move.Item1);
                unconsolidatedCount--;    
            }
    
            Console.WriteLine("Moves: " + sum);
        }
    

    Without more detail in your question, I can't guarantee that this actually meets the specification. But it does produce the value 4 for the sum. :)

    0 讨论(0)
  • 2021-01-25 11:06

    When you consolidate mine i into mine j, the amount of gold in the mine j is increased. This makes consolidations from mine j to other mines more expensive potentially making the ordering of the mines by the move cost invalid. To fix this, you could re-sort the list of mines at the beginning of each iteration of your while-loop.

    0 讨论(0)
提交回复
热议问题