Task: Transportation problem



C#: using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace TransportationProblem {
    class Shipment {
        public Shipment(double q, double cpu, int r, int c) {
            Quantity = q;
            CostPerUnit = cpu;
            R = r;
            C = c;
        }

        public double CostPerUnit { get; }

        public double Quantity { get; set; }

        public int R { get; }

        public int C { get; }
    }

    class Program {
        private static int[] demand;
        private static int[] supply;
        private static double[,] costs;
        private static Shipment[,] matrix;

        static void Init(string filename) {
            string line;
            using (StreamReader file = new StreamReader(filename)) {
                line = file.ReadLine();
                var numArr = line.Split();
                int numSources = int.Parse(numArr[0]);
                int numDestinations = int.Parse(numArr[1]);

                List<int> src = new List<int>();
                List<int> dst = new List<int>();

                line = file.ReadLine();
                numArr = line.Split();
                for (int i = 0; i < numSources; i++) {
                    src.Add(int.Parse(numArr[i]));
                }

                line = file.ReadLine();
                numArr = line.Split();
                for (int i = 0; i < numDestinations; i++) {
                    dst.Add(int.Parse(numArr[i]));
                }

                
                int totalSrc = src.Sum();
                int totalDst = dst.Sum();
                if (totalSrc > totalDst) {
                    dst.Add(totalSrc - totalDst);
                } else if (totalDst > totalSrc) {
                    src.Add(totalDst - totalSrc);
                }

                supply = src.ToArray();
                demand = dst.ToArray();

                costs = new double[supply.Length, demand.Length];
                matrix = new Shipment[supply.Length, demand.Length];

                for (int i = 0; i < numSources; i++) {
                    line = file.ReadLine();
                    numArr = line.Split();
                    for (int j = 0; j < numDestinations; j++) {
                        costs[i, j] = int.Parse(numArr[j]);
                    }
                }
            }
        }

        static void NorthWestCornerRule() {
            for (int r = 0, northwest = 0; r < supply.Length; r++) {
                for (int c = northwest; c < demand.Length; c++) {
                    int quantity = Math.Min(supply[r], demand[c]);
                    if (quantity > 0) {
                        matrix[r, c] = new Shipment(quantity, costs[r, c], r, c);

                        supply[r] -= quantity;
                        demand[c] -= quantity;

                        if (supply[r] == 0) {
                            northwest = c;
                            break;
                        }
                    }
                }
            }
        }

        static void SteppingStone() {
            double maxReduction = 0;
            Shipment[] move = null;
            Shipment leaving = null;

            FixDegenerateCase();

            for (int r = 0; r < supply.Length; r++) {
                for (int c = 0; c < demand.Length; c++) {
                    if (matrix[r, c] != null) {
                        continue;
                    }

                    Shipment trial = new Shipment(0, costs[r, c], r, c);
                    Shipment[] path = GetClosedPath(trial);

                    double reduction = 0;
                    double lowestQuantity = int.MaxValue;
                    Shipment leavingCandidate = null;

                    bool plus = true;
                    foreach (var s in path) {
                        if (plus) {
                            reduction += s.CostPerUnit;
                        } else {
                            reduction -= s.CostPerUnit;
                            if (s.Quantity < lowestQuantity) {
                                leavingCandidate = s;
                                lowestQuantity = s.Quantity;
                            }
                        }
                        plus = !plus;
                    }
                    if (reduction < maxReduction) {
                        move = path;
                        leaving = leavingCandidate;
                        maxReduction = reduction;
                    }
                }
            }

            if (move != null) {
                double q = leaving.Quantity;
                bool plus = true;
                foreach (var s in move) {
                    s.Quantity += plus ? q : -q;
                    matrix[s.R, s.C] = s.Quantity == 0 ? null : s;
                    plus = !plus;
                }
                SteppingStone();
            }
        }

        static List<Shipment> MatrixToList() {
            List<Shipment> newList = new List<Shipment>();
            foreach (var item in matrix) {
                if (null != item) {
                    newList.Add(item);
                }
            }
            return newList;
        }

        static Shipment[] GetClosedPath(Shipment s) {
            List<Shipment> path = MatrixToList();
            path.Add(s);

            
            
            int before;
            do {
                before = path.Count;
                path.RemoveAll(ship => {
                    var nbrs = GetNeighbors(ship, path);
                    return nbrs[0] == null || nbrs[1] == null;
                });
            } while (before != path.Count);

            
            Shipment[] stones = path.ToArray();
            Shipment prev = s;
            for (int i = 0; i < stones.Length; i++) {
                stones[i] = prev;
                prev = GetNeighbors(prev, path)[i % 2];
            }
            return stones;
        }

        static Shipment[] GetNeighbors(Shipment s, List<Shipment> lst) {
            Shipment[] nbrs = new Shipment[2];
            foreach (var o in lst) {
                if (o != s) {
                    if (o.R == s.R && nbrs[0] == null) {
                        nbrs[0] = o;
                    } else if (o.C == s.C && nbrs[1] == null) {
                        nbrs[1] = o;
                    }
                    if (nbrs[0] != null && nbrs[1] != null) {
                        break;
                    }
                }
            }
            return nbrs;
        }

        static void FixDegenerateCase() {
            const double eps = double.Epsilon;
            if (supply.Length + demand.Length - 1 != MatrixToList().Count) {
                for (int r = 0; r < supply.Length; r++) {
                    for (int c = 0; c < demand.Length; c++) {
                        if (matrix[r, c] == null) {
                            Shipment dummy = new Shipment(eps, costs[r, c], r, c);
                            if (GetClosedPath(dummy).Length == 0) {
                                matrix[r, c] = dummy;
                                return;
                            }
                        }
                    }
                }
            }
        }
        
        static void PrintResult(string filename) {
            Console.WriteLine("Optimal solution {0}\n", filename);
            double totalCosts = 0;

            for (int r = 0; r < supply.Length; r++) {
                for (int c = 0; c < demand.Length; c++) {
                    Shipment s = matrix[r, c];
                    if (s != null && s.R == r && s.C == c) {
                        Console.Write(" {0,3} ", s.Quantity);
                        totalCosts += (s.Quantity * s.CostPerUnit);
                    } else {
                        Console.Write("  -  ");
                    }
                }
                Console.WriteLine();
            }
            Console.WriteLine("\nTotal costs: {0}\n", totalCosts);
        }

        static void Main() {
            foreach (var filename in new string[] { "input1.txt", "input2.txt", "input3.txt" }) {
                Init(filename);
                NorthWestCornerRule();
                SteppingStone();
                PrintResult(filename);
            }
        }
    }
}



Java: import java.io.File;
import java.util.*;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toCollection;

public class TransportationProblem {

    private static int[] demand;
    private static int[] supply;
    private static double[][] costs;
    private static Shipment[][] matrix;

    private static class Shipment {
        final double costPerUnit;
        final int r, c;
        double quantity;

        public Shipment(double q, double cpu, int r, int c) {
            quantity = q;
            costPerUnit = cpu;
            this.r = r;
            this.c = c;
        }
    }

    static void init(String filename) throws Exception {

        try (Scanner sc = new Scanner(new File(filename))) {
            int numSources = sc.nextInt();
            int numDestinations = sc.nextInt();

            List<Integer> src = new ArrayList<>();
            List<Integer> dst = new ArrayList<>();

            for (int i = 0; i < numSources; i++)
                src.add(sc.nextInt());

            for (int i = 0; i < numDestinations; i++)
                dst.add(sc.nextInt());

            
            int totalSrc = src.stream().mapToInt(i -> i).sum();
            int totalDst = dst.stream().mapToInt(i -> i).sum();
            if (totalSrc > totalDst)
                dst.add(totalSrc - totalDst);
            else if (totalDst > totalSrc)
                src.add(totalDst - totalSrc);

            supply = src.stream().mapToInt(i -> i).toArray();
            demand = dst.stream().mapToInt(i -> i).toArray();

            costs = new double[supply.length][demand.length];
            matrix = new Shipment[supply.length][demand.length];

            for (int i = 0; i < numSources; i++)
                for (int j = 0; j < numDestinations; j++)
                    costs[i][j] = sc.nextDouble();
        }
    }

    static void northWestCornerRule() {

        for (int r = 0, northwest = 0; r < supply.length; r++)
            for (int c = northwest; c < demand.length; c++) {

                int quantity = Math.min(supply[r], demand[c]);
                if (quantity > 0) {
                    matrix[r][c] = new Shipment(quantity, costs[r][c], r, c);

                    supply[r] -= quantity;
                    demand[c] -= quantity;

                    if (supply[r] == 0) {
                        northwest = c;
                        break;
                    }
                }
            }
    }

    static void steppingStone() {
        double maxReduction = 0;
        Shipment[] move = null;
        Shipment leaving = null;

        fixDegenerateCase();

        for (int r = 0; r < supply.length; r++) {
            for (int c = 0; c < demand.length; c++) {

                if (matrix[r][c] != null)
                    continue;

                Shipment trial = new Shipment(0, costs[r][c], r, c);
                Shipment[] path = getClosedPath(trial);

                double reduction = 0;
                double lowestQuantity = Integer.MAX_VALUE;
                Shipment leavingCandidate = null;

                boolean plus = true;
                for (Shipment s : path) {
                    if (plus) {
                        reduction += s.costPerUnit;
                    } else {
                        reduction -= s.costPerUnit;
                        if (s.quantity < lowestQuantity) {
                            leavingCandidate = s;
                            lowestQuantity = s.quantity;
                        }
                    }
                    plus = !plus;
                }
                if (reduction < maxReduction) {
                    move = path;
                    leaving = leavingCandidate;
                    maxReduction = reduction;
                }
            }
        }

        if (move != null) {
            double q = leaving.quantity;
            boolean plus = true;
            for (Shipment s : move) {
                s.quantity += plus ? q : -q;
                matrix[s.r][s.c] = s.quantity == 0 ? null : s;
                plus = !plus;
            }
            steppingStone();
        }
    }

    static LinkedList<Shipment> matrixToList() {
        return stream(matrix)
                .flatMap(row -> stream(row))
                .filter(s -> s != null)
                .collect(toCollection(LinkedList::new));
    }

    static Shipment[] getClosedPath(Shipment s) {
        LinkedList<Shipment> path = matrixToList();
        path.addFirst(s);

        
        
        while (path.removeIf(e -> {
            Shipment[] nbrs = getNeighbors(e, path);
            return nbrs[0] == null || nbrs[1] == null;
        }));

        
        Shipment[] stones = path.toArray(new Shipment[path.size()]);
        Shipment prev = s;
        for (int i = 0; i < stones.length; i++) {
            stones[i] = prev;
            prev = getNeighbors(prev, path)[i % 2];
        }
        return stones;
    }

    static Shipment[] getNeighbors(Shipment s, LinkedList<Shipment> lst) {
        Shipment[] nbrs = new Shipment[2];
        for (Shipment o : lst) {
            if (o != s) {
                if (o.r == s.r && nbrs[0] == null)
                    nbrs[0] = o;
                else if (o.c == s.c && nbrs[1] == null)
                    nbrs[1] = o;
                if (nbrs[0] != null && nbrs[1] != null)
                    break;
            }
        }
        return nbrs;
    }

    static void fixDegenerateCase() {
        final double eps = Double.MIN_VALUE;

        if (supply.length + demand.length - 1 != matrixToList().size()) {

            for (int r = 0; r < supply.length; r++)
                for (int c = 0; c < demand.length; c++) {
                    if (matrix[r][c] == null) {
                        Shipment dummy = new Shipment(eps, costs[r][c], r, c);
                        if (getClosedPath(dummy).length == 0) {
                            matrix[r][c] = dummy;
                            return;
                        }
                    }
                }
        }
    }

    static void printResult(String filename) {
        System.out.printf("Optimal solution %s%n%n", filename);
        double totalCosts = 0;

        for (int r = 0; r < supply.length; r++) {
            for (int c = 0; c < demand.length; c++) {

                Shipment s = matrix[r][c];
                if (s != null && s.r == r && s.c == c) {
                    System.out.printf(" %3s ", (int) s.quantity);
                    totalCosts += (s.quantity * s.costPerUnit);
                } else
                    System.out.printf("  -  ");
            }
            System.out.println();
        }
        System.out.printf("%nTotal costs: %s%n%n", totalCosts);
    }

    public static void main(String[] args) throws Exception {

        for (String filename : new String[]{"input1.txt", "input2.txt",
            "input3.txt"}) {
            init(filename);
            northWestCornerRule();
            steppingStone();
            printResult(filename);
        }
    }
}