using System;
using System.Collections.Generic;

class Node
{
	public enum Colors
	{
		Black, White, Gray
	}

	public Colors color { get; set; }
	public int N { get; }

	public Node(int n)
	{
		N = n;
		color = Colors.White;
	}
}

class Graph
{
	public HashSet<Node> V { get; }
	public Dictionary<Node, HashSet<Node>> Adj { get; }

	/// <summary>
	/// Kosaraju's strongly connected components algorithm
	/// </summary>
	public void Kosaraju()
	{
		var L = new HashSet<Node>();

		Action<Node> Visit = null;
		Visit = (u) =>
		{
			if (u.color == Node.Colors.White)
			{
				u.color = Node.Colors.Gray;

				foreach (var v in Adj[u])
					Visit(v);

				L.Add(u);
			}
		};

		Action<Node, Node> Assign = null;
		Assign = (u, root) =>
		{
			if (u.color != Node.Colors.Black)
			{
				if (u == root)
					Console.Write("SCC: ");

				Console.Write(u.N + " ");
				u.color = Node.Colors.Black;

				foreach (var v in Adj[u])
					Assign(v, root);

				if (u == root)
					Console.WriteLine();
			}
		};

		foreach (var u in V)
			Visit(u);

		foreach (var u in L)
			Assign(u, u);
	}
}


#include <functional>
#include <iostream>
#include <ostream>
#include <vector>

template<typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
    auto it = v.cbegin();
    auto end = v.cend();

    os << "[";
    if (it != end) {
        os << *it;
        it = std::next(it);
    }
    while (it != end) {
        os << ", " << *it;
        it = std::next(it);
    }
    return os << "]";
}

std::vector<int> kosaraju(std::vector<std::vector<int>>& g) {
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    auto size = g.size();
    std::vector<bool> vis(size);           // all false by default
    std::vector<int> l(size);              // all zero by default
    auto x = size;                         // index for filling l in reverse order
    std::vector<std::vector<int>> t(size); // transpose graph

    // Recursive subroutine 'visit':
    std::function<void(int)> visit;
    visit = [&](int u) {
        if (!vis[u]) {
            vis[u] = true;
            for (auto v : g[u]) {
                visit(v);
                t[v].push_back(u); // construct transpose
            }
            l[--x] = u;
        }
    };

    // 2. For each vertex u of the graph do visit(u)
    for (int i = 0; i < g.size(); ++i) {
        visit(i);
    }
    std::vector<int> c(size); // used for component assignment

    // Recursive subroutine 'assign':
    std::function<void(int, int)> assign;
    assign = [&](int u, int root) {
        if (vis[u]) { // repurpose vis to mean 'unassigned'
            vis[u] = false;
            c[u] = root;
            for (auto v : t[u]) {
                assign(v, root);
            }
        }
    };

    // 3: For each element u of l in order, do assign(u, u)
    for (auto u : l) {
        assign(u, u);
    }

    return c;
}

std::vector<std::vector<int>> g = {
    {1},
    {2},
    {0},
    {1, 2, 4},
    {3, 5},
    {2, 6},
    {5},
    {4, 6, 7},
};

int main() {
    using namespace std;

    cout << kosaraju(g) << endl;

    return 0;
}


/// # Panics
///
/// If string is empty.
fn first_char(string: &str) -> char {
    string.chars().next().unwrap()
}

/// # Panics
///
/// If string is empty.
fn first_and_last_char(string: &str) -> (char, char) {
    (
        first_char(string),
        first_char(string.rmatches(|_: char| true).next().unwrap()),
    )
}

struct Pokemon {
    name: &'static str,
    first: char,
    last: char,
}

impl Pokemon {
    fn new(name: &'static str) -> Pokemon {
        let (first, last) = first_and_last_char(name);
        Pokemon { name, first, last }
    }
}

#[derive(Default)]
struct App {
    max_path_length: usize,
    max_path_length_count: usize,
    max_path_example: Vec<&'static str>,
    pokemon: Vec<Pokemon>,
}

impl App {
    fn search(&mut self, offset: usize) {
        if offset > self.max_path_length {
            self.max_path_length = offset;
            self.max_path_length_count = 1;
        } else if offset == self.max_path_length {
            self.max_path_length_count += 1;
            self.max_path_example.clear();
            self.max_path_example.extend(
                self.pokemon[0..offset]
                    .iter()
                    .map(|Pokemon { name, .. }| *name),
            );
        }

        let last_char = self.pokemon[offset - 1].last;
        for i in offset..self.pokemon.len() {
            if self.pokemon[i].first == last_char {
                self.pokemon.swap(offset, i);
                self.search(offset + 1);
                self.pokemon.swap(offset, i);
            }
        }
    }
}

fn main() {
    let pokemon_names = [
        "audino",
        "bagon",
        "baltoy",
        "banette",
        "bidoof",
        "braviary",
        "bronzor",
        "carracosta",
        "charmeleon",
        "cresselia",
        "croagunk",
        "darmanitan",
        "deino",
        "emboar",
        "emolga",
        "exeggcute",
        "gabite",
        "girafarig",
        "gulpin",
        "haxorus",
        "heatmor",
        "heatran",
        "ivysaur",
        "jellicent",
        "jumpluff",
        "kangaskhan",
        "kricketune",
        "landorus",
        "ledyba",
        "loudred",
        "lumineon",
        "lunatone",
        "machamp",
        "magnezone",
        "mamoswine",
        "nosepass",
        "petilil",
        "pidgeotto",
        "pikachu",
        "pinsir",
        "poliwrath",
        "poochyena",
        "porygon2",
        "porygonz",
        "registeel",
        "relicanth",
        "remoraid",
        "rufflet",
        "sableye",
        "scolipede",
        "scrafty",
        "seaking",
        "sealeo",
        "silcoon",
        "simisear",
        "snivy",
        "snorlax",
        "spoink",
        "starly",
        "tirtouga",
        "trapinch",
        "treecko",
        "tyrogue",
        "vigoroth",
        "vulpix",
        "wailord",
        "wartortle",
        "whismur",
        "wingull",
        "yamask",
    ];

    let mut app = App {
        pokemon: pokemon_names
            .iter()
            .map(|name| Pokemon::new(name))
            .collect(),
        ..App::default()
    };

    for i in 0..app.pokemon.len() {
        app.pokemon.swap(0, i);
        app.search(1);
        app.pokemon.swap(0, i);
    }

    println!("Maximum path length: {}", app.max_path_length);
    println!("Paths of that length: {}", app.max_path_length_count);
    println!(
        "Example path of that length: {}",
        app.max_path_example.join(" "),
    );
}


object LastLetterFirstLetterNaive extends App {
  def solve(names: Set[String]) = {
    def extend(solutions: List[List[String]]): List[List[String]] = {
      val more = solutions.flatMap{solution =>
        val lastLetter = solution.head takeRight 1
        (names -- solution).filter(_.take(1) equalsIgnoreCase lastLetter).map(_ :: solution)
      }
      if (more.isEmpty) solutions else extend(more)
    }

    extend(names.toList.map(List(_))).map(_.reverse)
  }

  val names70 = Set("audino", "bagon", "baltoy", "banette", "bidoof", "braviary", "bronzor", "carracosta", "charmeleon", "cresselia", "croagunk", "darmanitan", "deino", "emboar", "emolga", "exeggcute", "gabite", "girafarig", "gulpin", "haxorus", "heatmor", "heatran", "ivysaur", "jellicent", "jumpluff", "kangaskhan", "kricketune", "landorus", "ledyba", "loudred", "lumineon", "lunatone", "machamp", "magnezone", "mamoswine", "nosepass", "petilil", "pidgeotto", "pikachu", "pinsir", "poliwrath", "poochyena", "porygon2", "porygonz", "registeel", "relicanth", "remoraid", "rufflet", "sableye", "scolipede", "scrafty", "seaking", "sealeo", "silcoon", "simisear", "snivy", "snorlax", "spoink", "starly", "tirtouga", "trapinch", "treecko", "tyrogue", "vigoroth", "vulpix", "wailord", "wartortle", "whismur", "wingull", "yamask")

  val solutions = solve(names70)
  println(s"Maximum path length: ${solutions.head.length}")
  println(s"Paths of that length: ${solutions.size}")
  println("Example path of that length:")
  println(solutions.head.sliding(7,7).map(_.mkString(" ")).map("  "+_).mkString("\n"))
}


import std.container.array;
import std.stdio;

/* the list index is the first vertex in the edge(s) */
auto g = [
    [1],
    [2],
    [0],
    [1, 2, 4],
    [3, 5],
    [2, 6],
    [5],
    [4, 6, 7],
];

int[] kosaraju(int[][] g) {
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    auto size = g.length; // all false by default
    Array!bool vis;
    vis.length = size;
    int[] l;              // all zero by default
    l.length = size;
    auto x = size;        // index for filling l in reverse order
    int[][] t;            // transpose graph
    t.length = size;

    // Recursive subroutine 'visit':
    void visit(int u) {
        if (!vis[u]) {
            vis[u] = true;
            foreach (v; g[u]) {
                visit(v);
                t[v] ~= u;  // construct transpose
            }
            l[--x] = u;
        }
     }

    // 2. For each vertex u of the graph do visit(u)
    foreach (u, _; g) {
        visit(u);
    }
    int[] c;  // used for component assignment
    c.length = size;

    // Recursive subroutine 'assign':
    void assign(int u, int root) {
        if (vis[u]) {  // repurpose vis to mean 'unassigned'
            vis[u] = false;
            c[u] = root;
            foreach(v; t[u]) {
                assign(v, root);
            }
        }
    }

    // 3: For each element u of l in order, do assign(u, u)
    foreach (u; l) {
        assign(u, u);
    }

    return c;
}

void main() {
    writeln(kosaraju(g));
}


program KosarajuApp;

uses
  System.SysUtils;

type
  TKosaraju = TArray<TArray<Integer>>;

var
  g: TKosaraju;

procedure Init();
begin
  SetLength(g, 8);
  g[0] := [1];
  g[1] := [2];
  g[2] := [0];
  g[3] := [1, 2, 4];
  g[4] := [3, 5];
  g[5] := [2, 6];
  g[6] := [5];
  g[7] := [4, 6, 7];
end;

procedure Println(vector: TArray<Integer>);
var
  i: Integer;
begin
  write('[');
  if (Length(vector) > 0) then
    for i := 0 to High(vector) do
    begin
      write(vector[i]);
      if (i < high(vector)) then
        write(', ');
    end;

  writeln(']');
end;

function Kosaraju(g: TKosaraju): TArray<Integer>;
var
  vis: TArray<Boolean>;
  L, c: TArray<Integer>;
  x: Integer;
  t: TArray<TArray<Integer>>;
  Visit: TProc<Integer>;
  u: Integer;
  Assign: TProc<Integer, Integer>;
begin
  // 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
  SetLength(vis, Length(g));
  SetLength(L, Length(g));
  x := Length(L);
  // index for filling L in reverse order
  SetLength(t, Length(g)); // transpose graph

  // 2. recursive subroutine:

  Visit := procedure(u: Integer)
    begin
      if (not vis[u]) then
      begin
        vis[u] := true;
        for var v in g[u] do
        begin
          Visit(v);
          t[v] := concat(t[v], [u]);
          // construct transpose
        end;

        dec(x);
        L[x] := u;
      end;
    end;

  // 2. For each vertex u of the graph do Visit(u)

  for u := 0 to High(g) do
  begin
    Visit(u);
  end;

  SetLength(c, Length(g)); // result, the component assignment

  // 3: recursive subroutine:

  Assign := procedure(u, root: Integer)
    begin
      if vis[u] then
      // repurpose vis to mean "unassigned"
      begin
        vis[u] := false;
        c[u] := root;

        for var v in t[u] do
          Assign(v, root);
      end;
    end;

  // 3: For each element u of L in order, do Assign(u,u)

  for u in L do
    Assign(u, u);

  Result := c;
end;

begin
  Init;
  Println(Kosaraju(g));
end.


$ include "seed7_05.s7i";

var integer: maxPathLength is 0;
var integer: maxPathLengthCount is 0;
var string: maxPathExample is "";

var array string: names is [] (
    "audino", "bagon", "baltoy", "banette", "bidoof", "braviary", "bronzor",
    "carracosta", "charmeleon", "cresselia", "croagunk", "darmanitan", "deino",
    "emboar", "emolga", "exeggcute", "gabite", "girafarig", "gulpin", "haxorus",
    "heatmor", "heatran", "ivysaur", "jellicent", "jumpluff", "kangaskhan",
    "kricketune", "landorus", "ledyba", "loudred", "lumineon", "lunatone",
    "machamp", "magnezone", "mamoswine", "nosepass", "petilil", "pidgeotto",
    "pikachu", "pinsir", "poliwrath", "poochyena", "porygon2", "porygonz",
    "registeel", "relicanth", "remoraid", "rufflet", "sableye", "scolipede",
    "scrafty", "seaking", "sealeo", "silcoon", "simisear", "snivy", "snorlax",
    "spoink", "starly", "tirtouga", "trapinch", "treecko", "tyrogue", "vigoroth",
    "vulpix", "wailord", "wartortle", "whismur", "wingull", "yamask");

const proc: recursive (in array string: part, in integer: offset) is func
  local
    var integer: index is 0;
    var char: lastChar is ' ';
    var string: tmp is "";
  begin
    if pred(offset) > maxPathLength then
      maxPathLength := pred(offset);
      maxPathLengthCount := 1;
    elsif pred(offset) = maxPathLength then
      incr(maxPathLengthCount);
      maxPathExample := "";
      for index range 1 to pred(offset) do
        if pred(index) rem 5 = 0 then
          maxPathExample &:= "\n  ";
        else
          maxPathExample &:= " ";
        end if;
        maxPathExample &:= part[index];
      end for;
    end if;
    lastChar := part[pred(offset)][length(part[pred(offset)])];
    for index range offset to length(part) do
      if part[index][1] = lastChar then
        tmp := names[offset];
        names[offset] := names[index];
        names[index] := tmp;
        recursive(names, succ(offset));
        names[index] := names[offset];
        names[offset] := tmp;
      end if;
    end for;
  end func;

const proc: main is func
  local
    var integer: index is 0;
    var string: tmp is "";
  begin
    for index range 1 to length(names) do
      tmp := names[1];
      names[1] := names[index];
      names[index] := tmp;
      recursive(names, 2);
      names[index] := names[1];
      names[1] := tmp;
    end for;
    writeln("maximum path length:  " <& maxPathLength lpad 4);
    writeln("paths of that length: " <& maxPathLengthCount lpad 4);
    writeln("example path of that length:"  <& maxPathExample);
  end func;


class LLFL(Array words) {

    has f = Hash()

    method init {
        words.each {|w|
            var m = w.match(/^(.).*(.)$/)
            f{m[0]}{w} = m[1]
        }
    }

    method longest_chain {

        var stack   = []
        var longest = []

        func poke(c) {
            var h = f{c}

            h.each_k { |word|
                var v = h.delete(word)
                stack.push(word)
                longest[] = stack[] if (stack.len > longest.len)
                __FUNC__(v) if f.exists(v)
                stack.pop
                h{word} = v
            }
        }

        f.each_k { poke(_) }
        return longest
    }
}

var words = %w(
  audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon
  cresselia croagunk darmanitan deino emboar emolga exeggcute gabite
  girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan
  kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine
  nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2
  porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking
  sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko
  tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask
)

var obj = LLFL(words)
var longest = obj.longest_chain()

say "#{longest.len}: #{longest.join(' ')}"


package main

import "fmt"

var g = [][]int{
    0: {1},
    1: {2},
    2: {0},
    3: {1, 2, 4},
    4: {3, 5},
    5: {2, 6},
    6: {5},
    7: {4, 6, 7},
}

func main() {
    fmt.Println(kosaraju(g))
}

func kosaraju(g [][]int) []int {
    // 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
    vis := make([]bool, len(g))
    L := make([]int, len(g))
    x := len(L)                // index for filling L in reverse order
    t := make([][]int, len(g)) // transpose graph
    // 2. recursive subroutine:
    var Visit func(int)
    Visit = func(u int) {
        if !vis[u] {
            vis[u] = true
            for _, v := range g[u] {
                Visit(v)
                t[v] = append(t[v], u) // construct transpose
            }
            x--
            L[x] = u
        }
    }
    // 2. For each vertex u of the graph do Visit(u)
    for u := range g {
        Visit(u)
    }
    c := make([]int, len(g)) // result, the component assignment
    // 3: recursive subroutine:
    var Assign func(int, int)
    Assign = func(u, root int) {
        if vis[u] { // repurpose vis to mean "unassigned"
            vis[u] = false
            c[u] = root
            for _, v := range t[u] {
                Assign(v, root)
            }
        }
    }
    // 3: For each element u of L in order, do Assign(u,u)
    for _, u := range L {
        Assign(u, u)
    }
    return c
}


visit=: {{
  if.y{unvisited do.
    unvisited=: 0 y} unvisited
    visit y{::out
    L=: y,L
  end.
}}"0

assign=: {{
  if._1=y{assigned do.
    assigned=: x y} assigned
    x&assign y{::in
  end.
}}"0

kosaraju=: {{
  out=: y
  in=: <@I.|:y e.S:0~i.#y
  unvisited=: 1#~#y
  assigned=: _1#~#y
  L=: i.0
  visit"0 i.#y
  assign~L
  assigned
}}


proc search {path arcs} {
    set solutions {}
    set c [string index [lindex $path end] end]
    set i -1
    foreach arc $arcs {
	incr i
	if {[string index $arc 0] ne $c} continue
	set soln [search [concat $path [list $arc]] [lreplace $arcs $i $i]]
	lappend solutions [list [llength $soln] $soln]
    }
    if {[llength $solutions]} {
	return [lindex [lsort -integer -decreasing -index 0 $solutions] 0 1]
    } else {
	return $path
    }
}
proc firstlast names {
    set solutions {}
    set i -1
    foreach initial $names {
	incr i
	set soln [search [list $initial] [lreplace $names $i $i]]
	lappend solutions [list [llength $soln] $soln]
    }
    return [lindex [lsort -integer -decreasing -index 0 $solutions] 0 1]
}

set names {
    audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon
    cresselia croagunk darmanitan deino emboar emolga exeggcute gabite
    girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff
    kangaskhan kricketune landorus ledyba loudred lumineon lunatone machamp
    magnezone mamoswine nosepass petilil pidgeotto pikachu pinsir poliwrath
    poochyena porygon2 porygonz registeel relicanth remoraid rufflet sableye
    scolipede scrafty seaking sealeo silcoon simisear snivy snorlax spoink
    starly tirtouga trapinch treecko tyrogue vigoroth vulpix wailord wartortle
    whismur wingull yamask
}
set path [firstlast $names]
puts "Path (length: [llength $path]): $path"


#import std

mon =

~&*~ sep`  mat`  -[
   audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon
   cresselia croagunk darmanitan deino emboar emolga exeggcute gabite
   girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan
   kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine
   nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2
   porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking
   sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko
   tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask]-

poke = @iiDrzhK16rlXOASK24PiX ~&llrHiFPrYX^=rxS^|\~&iNCS *=+ ~&rlwNrlCQ^*D/~&+ @h

#show+

example = ~&h poke mon


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.IntConsumer;
import java.util.stream.Collectors;

public class Kosaraju {
    static class Recursive<I> {
        I func;
    }

    private static List<Integer> kosaraju(List<List<Integer>> g) {
        // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
        int size = g.size();
        boolean[] vis = new boolean[size];
        int[] l = new int[size];
        AtomicInteger x = new AtomicInteger(size);

        List<List<Integer>> t = new ArrayList<>();
        for (int i = 0; i < size; ++i) {
            t.add(new ArrayList<>());
        }

        Recursive<IntConsumer> visit = new Recursive<>();
        visit.func = (int u) -> {
            if (!vis[u]) {
                vis[u] = true;
                for (Integer v : g.get(u)) {
                    visit.func.accept(v);
                    t.get(v).add(u);
                }
                int xval = x.decrementAndGet();
                l[xval] = u;
            }
        };

        // 2. For each vertex u of the graph do visit(u)
        for (int i = 0; i < size; ++i) {
            visit.func.accept(i);
        }
        int[] c = new int[size];

        Recursive<BiConsumer<Integer, Integer>> assign = new Recursive<>();
        assign.func = (Integer u, Integer root) -> {
            if (vis[u]) {  // repurpose vis to mean 'unassigned'
                vis[u] = false;
                c[u] = root;
                for (Integer v : t.get(u)) {
                    assign.func.accept(v, root);
                }
            }
        };

        // 3: For each element u of l in order, do assign(u, u)
        for (int u : l) {
            assign.func.accept(u, u);
        }

        return Arrays.stream(c).boxed().collect(Collectors.toList());
    }

    public static void main(String[] args) {
        List<List<Integer>> g = new ArrayList<>();
        for (int i = 0; i < 8; ++i) {
            g.add(new ArrayList<>());
        }
        g.get(0).add(1);
        g.get(1).add(2);
        g.get(2).add(0);
        g.get(3).add(1);
        g.get(3).add(2);
        g.get(3).add(4);
        g.get(4).add(3);
        g.get(4).add(5);
        g.get(5).add(2);
        g.get(5).add(6);
        g.get(6).add(5);
        g.get(7).add(4);
        g.get(7).add(6);
        g.get(7).add(7);

        List<Integer> output = kosaraju(g);
        System.out.println(output);
    }
}


' Last letter-first letter - VBScript - 11/03/2019
    names = array( _
        "audino", "bagon", "baltoy", "banette", _
        "bidoof", "braviary", "bronzor", "carracosta", "charmeleon", _
        "cresselia", "croagunk", "darmanitan", "deino", "emboar", _
        "emolga", "exeggcute", "gabite", "girafarig", "gulpin", _
        "haxorus", "heatmor", "heatran", "ivysaur", "jellicent", _
        "jumpluff", "kangaskhan", "kricketune", "landorus", "ledyba", _
        "loudred", "lumineon", "lunatone", "machamp", "magnezone", _
        "mamoswine", "nosepass", "petilil", "pidgeotto", "pikachu", _
        "pinsir", "poliwrath", "poochyena", "porygon2", "porygonz", _
        "registeel", "relicanth", "remoraid", "rufflet", "sableye", _
        "scolipede", "scrafty", "seaking", "sealeo", "silcoon", _
        "simisear", "snivy", "snorlax", "spoink", "starly", "tirtouga", _
        "trapinch", "treecko", "tyrogue", "vigoroth", "vulpix", _
        "wailord", "wartortle", "whismur", "wingull", "yamask")

    maxPathLength = 0
    maxPathLengthCount = 0
    maxPathExample = ""
    t1=timer

    For i = 0 To ubound(names)
        'swap names(0), names(i)
        temp=names(0): names(0)=names(i): names(i)=temp
        Call lastfirst(names, 1)
        'swap names(0), names(i)
        temp=names(0): names(0)=names(i): names(i)=temp
    Next 'i
    buf = buf & "Maximum length = " & maxPathLength & vbCrLf
    buf = buf & "Number of solutions with that length = " & maxPathLengthCount & vbCrLf
    buf = buf & "One such solution: "  & vbCrLf & maxPathExample & vbCrLf
    t2=timer
    MsgBox buf,,"Last letter-first letter - " & Int(t2-t1) & " sec"

Sub lastfirst(names, offset)
    dim i, l
    If offset > maxPathLength Then
        maxPathLength = offset
        maxPathLengthCount = 1
    ElseIf offset = maxPathLength Then
        maxPathLengthCount = maxPathLengthCount + 1
        maxPathExample = ""
        For i = 0 To offset-1
            maxPathExample = maxPathExample & names(i) & vbCrLf
        Next 'i
    End If
    l = Right(names(offset - 1),1)
    For i = offset To ubound(names)
        If Left(names(i),1) = l Then
            'swap names(i), names(offset)
            temp=names(offset): names(offset)=names(i): names(i)=temp
            Call lastfirst(names, offset+1)
            'swap names(i), names(offset)
            temp=names(offset): names(offset)=names(i): names(i)=temp
        End If
    Next 'i
End Sub 'lastfirst


var maxPathLength = 0
var maxPathLengthCount = 0
var maxPathExample = ""

var names = [
    "audino", "bagon", "baltoy", "banette", "bidoof",
    "braviary", "bronzor", "carracosta", "charmeleon", "cresselia",
    "croagunk", "darmanitan", "deino", "emboar", "emolga",
    "exeggcute", "gabite", "girafarig", "gulpin", "haxorus",
    "heatmor", "heatran", "ivysaur", "jellicent", "jumpluff",
    "kangaskhan", "kricketune", "landorus", "ledyba", "loudred",
    "lumineon", "lunatone", "machamp", "magnezone", "mamoswine",
    "nosepass", "petilil", "pidgeotto", "pikachu", "pinsir",
    "poliwrath", "poochyena", "porygon2", "porygonz", "registeel",
    "relicanth", "remoraid", "rufflet", "sableye", "scolipede",
    "scrafty", "seaking", "sealeo", "silcoon", "simisear",
    "snivy", "snorlax", "spoink", "starly", "tirtouga",
    "trapinch", "treecko", "tyrogue", "vigoroth", "vulpix",
    "wailord", "wartortle", "whismur", "wingull", "yamask"
]

var search // recursive function
search = Fn.new { |part, offset|
    if (offset > maxPathLength) {
        maxPathLength = offset
        maxPathLengthCount = 1
    } else if (offset == maxPathLength) {
        maxPathLengthCount = maxPathLengthCount + 1
        maxPathExample = ""
        for (i in 0...offset) {
            maxPathExample = maxPathExample + ((i % 5 == 0) ? "\n  " : " ") + part[i]
        }
    }
    var lastChar = part[offset - 1][-1]
    for (i in offset...part.count) {
        if (part[i][0] == lastChar) {
            var tmp = names[offset]
            names[offset] = names[i]
            names[i] = tmp
            search.call(names, offset + 1)
            names[i] = names[offset]
            names[offset] = tmp
        }
    }
}

for (i in 0...names.count) {
    var tmp = names[0]
    names[0] = names[i]
    names[i] = tmp
    search.call(names, 1)
    names[i] = names[0]
    names[0] = tmp
}
System.print("Maximum path length         : %(maxPathLength)")
System.print("Paths of that length        : %(maxPathLengthCount)")
System.print("Example path of that length : %(maxPathExample)")


F maxnum(x)
   V maxlen = String(max(x)).len
   R sorted((x.map(v -> String(v))), key' i -> i * (@maxlen * 2 I/ i.len), reverse' 1B).join(‘’)

L(numbers) [[212, 21221], [1, 34, 3, 98, 9, 76, 45, 4], [54, 546, 548, 60]]
   print("Numbers: #.\n  Largest integer: #15".format(numbers, maxnum(numbers)))


# Fill an array of the specified length with the input value
def dimension($n): . as $in | [range(0;$n) | $in];

# $graph should be an adjacency-list graph with IO==0
def korasaju($graph):
  ($graph|length) as $length
  | def init: {
        vis: (false | dimension($length)),  # visited
        L: [],                              # for an array of $length integers
        t: ([]|dimension($length)),         # transposed graph
        x: $length                          # index
      };

    # input: {vis, L, t, x, t}
    def visit($u):
      if .vis[$u] | not
      then .vis[$u] = true
      |  reduce ($graph[$u][]) as $v (.;
              visit($v)
              | .t[$v] += [$u] )
      | .x -= 1
      | .L[.x] = $u
      else .
      end ;

    # input: {vis, t, c}
    def assign($u; $root):
      if .vis[$u]
      then .vis[$u] = false
      | .c[$u] = $root
      | reduce .t[$u][] as $v (.; assign($v; $root))
      else .
      end ;

    # For each vertex u of the graph, mark u as unvisited.
    init

    # For each vertex u of the graph do visit(u)
    | reduce range(0;$length) as $u (.; visit($u))
    | .c = (null|dimension($length))

    # For each element u of L in order, do assign(u, u)
    | reduce .L[] as $u (.; assign($u; $u) )
    | .c ;

# An example adjacency list using IO==1
def g: [
    [1],
    [2],
    [0],
    [1, 2, 4],
    [3, 5],
    [2, 6],
    [5],
    [4, 6, 7]
];

korasaju(g)


function korasaju(g::Vector{Vector{T}}) where T<:Integer
    # 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
    vis = falses(length(g))
    L   = Vector{T}(length(g))
    x   = length(L) + 1
    t   = collect(T[] for _ in eachindex(g))

    # Recursive
    function visit(u::T)
        if !vis[u]
            vis[u] = true
            for v in g[u]
                visit(v)
                push!(t[v], u)
            end
            x -= 1
            L[x] = u
        end
    end
    # 2. For each vertex u of the graph do visit(u)
    for u in eachindex(g)
        visit(u)
    end
    c = Vector{T}(length(g))
    # 3. Recursive subroutine:
    function assign(u::T, root::T)
        if vis[u]
            vis[u] = false
            c[u] = root
            for v in t[u]
                assign(v, root)
            end
        end
    end
    # 3. For each element u of L in order, do assign(u, u)
    for u in L
        assign(u, u)
    end
    return c
end

g = [[2], [3], [1], [2, 3, 5], [4, 6], [3, 7], [6], [5, 7, 8]]
println(korasaju(g))


// version 1.1.3

/* the list index is the first vertex in the edge(s) */
val g = listOf(
    intArrayOf(1),        // 0
    intArrayOf(2),        // 1
    intArrayOf(0),        // 2
    intArrayOf(1, 2, 4),  // 3
    intArrayOf(3, 5),     // 4
    intArrayOf(2, 6),     // 5
    intArrayOf(5),        // 6
    intArrayOf(4, 6, 7)   // 7
)

fun kosaraju(g: List<IntArray>): List<List<Int>> {
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    val size = g.size
    val vis = BooleanArray(size)                 // all false by default
    val l = IntArray(size)                       // all zero by default
    var x = size                                 // index for filling l in reverse order
    val t = List(size) { mutableListOf<Int>() }  // transpose graph

    // Recursive subroutine 'visit':
    fun visit(u: Int) {
        if (!vis[u]) {
            vis[u] = true
            for (v in g[u]) {
                visit(v)
                t[v].add(u)  // construct transpose
            }
            l[--x] = u
        }
     }

    // 2. For each vertex u of the graph do visit(u)
    for (u in g.indices) visit(u)
    val c = IntArray(size)  // used for component assignment

    // Recursive subroutine 'assign':
    fun assign(u: Int, root: Int) {
        if (vis[u]) {  // repurpose vis to mean 'unassigned'
            vis[u] = false
            c[u] = root
            for (v in t[u]) assign(v, root)
        }
    }

    // 3: For each element u of l in order, do assign(u, u)
    for (u in l) assign(u, u)

    // Obtain list of SCC's from 'c' and return it
    return c.withIndex()
            .groupBy { it.value }.values
            .map { ivl -> ivl.map { it.index } }
}

fun main(args: Array<String>) {
    println(kosaraju(g).joinToString("\n"))
}


all$ = "audino bagon baltoy banette bidoof braviary bronzor carracosta charmeleon "
all$ = all$ + "cresselia croagunk darmanitan deino emboar emolga exeggcute gabite "
all$ = all$ + "girafarig gulpin haxorus heatmor heatran ivysaur jellicent jumpluff kangaskhan "
all$ = all$ + "kricketune landorus ledyba loudred lumineon lunatone machamp magnezone mamoswine "
all$ = all$ + "nosepass petilil pidgeotto pikachu pinsir poliwrath poochyena porygon2 "
all$ = all$ + "porygonz registeel relicanth remoraid rufflet sableye scolipede scrafty seaking "
all$ = all$ + "sealeo silcoon simisear snivy snorlax spoink starly tirtouga trapinch treecko "
all$ = all$ + "tyrogue vigoroth vulpix wailord wartortle whismur wingull yamask"

dim word$(1)

lnames = token(all$, word$())

dim first(256), snext(lnames)

for i = 1 to lnames
    ch = asc(left$(word$(i), 1))
    if first(ch)=0 then
        first(ch) = i
    end if
    for j=i+1 to lnames
        if asc(left$(word$(j), 1))=ch then
            snext(i) = j
            break
        end if
    next
next

dim taken(lnames), best(lnames)

sub try(ch, last, n)
    local nex, i

    nex = first(ch)
    while(nex <> 0)
        if taken(nex)=0 then
            taken(last) = nex
            taken(nex) = -1
            try(asc(right$(word$(nex), 1)),nex,n+1)
            taken(last) = -1
            taken(nex) = 0
        end if
        nex = snext(nex)
    wend
    if n>maxn then
        bstart = tstart
        for i = 1 to lnames
            best(i) = taken(i)
        next
        maxn = n
        count = 1
    elsif n=maxn then
        count = count + 1
    end if
end sub

for i=1 to lnames
    tstart = i
    taken(i) = -1
    try(asc(right$(word$(i), 1)),i,1)
    taken(i) = 0
next

print "Runtime: ", peek("millisrunning")/1000, " seconds. Max length: ", maxn, ", found ", count, " of such, one of which is:\n"
do
    print word$(bstart), " ";
    bstart = best(bstart)
    if bstart = -1 break
loop


pokemon:=("audino bagon baltoy banette bidoof braviary "
   "bronzor carracosta charmeleon cresselia croagunk darmanitan deino "
   ...
   "whismur wingull yamask").split();

tree:=pokemon.pump(Dictionary(),'wrap(name){ //--> Hash("aB":("Bc","Bd",,,) )
   T( name, pokemon.filter('wrap(nm){ name[-1]==nm[0] }) )
});

fcn maxPath([(a,_)]ab,[(c,_)]cd){ if(a>c) ab else cd }
fcn walk(name,pathLen,path,tree){  //-->longest path for name
   names:=tree.find(name,T); tree[name]=T; // nuke cycle
   np:=names.reduce('wrap(np,name){
      maxPath(np,walk(name,pathLen+1,String(path," ",name),tree));
   },T(0,""));
   tree[name]=names;
   if(np[0]>pathLen) return(np);
   return(pathLen,path);
}

pokemon.reduce('wrap(np,name){ maxPath(walk(name,1,name,tree),np) },T(0,""))
.println();


function Order(Left, Right: Natural) return Boolean is
      ( (Img(Left) & Img(Right)) > (Img(Right) & Img(Left)) );


BEGIN
    # returns the integer value of s #
    OP TOINT = ( STRING s)INT:
    BEGIN
        INT result := 0;
        FOR s pos FROM LWB s TO UPB s DO
            result *:= 10 +:= ( ABS s[ s pos ] - ABS "0" )
        OD;
        result
    END # TOINT # ;
    # returns the first digit of n #
    OP FIRSTDIGIT = ( INT n )INT:
    BEGIN
        INT result := ABS n;
        WHILE result > 9 DO result OVERAB 10 OD;
        result
    END # FIRSTDIGIT # ;
    # returns a string representaton of n #
    OP TOSTRING = ( INT n )STRING: whole( n, 0 );
    # returns an array containing the values of a sorted such that concatenating the values would result in the largest value #
    OP CONCATSORT = ( []INT a )[]INT:
       IF LWB a >= UPB a THEN
           # 0 or 1 element(s) #
           a
       ELSE
           # 2 or more elements #
           [ 1 : ( UPB a - LWB a ) + 1 ]INT result := a[ AT 1 ];
           # sort the numbers into reverse first digit order #
           FOR o pos FROM UPB result - 1 BY -1 TO 1
           WHILE BOOL swapped := FALSE;
                 FOR i pos TO o pos DO
                     IF FIRSTDIGIT result[ i pos ] < FIRSTDIGIT result[ i pos + 1 ] THEN
                         INT t = result[ i pos + 1 ];
                         result[ i pos + 1 ] := result[ i pos ];
                         result[ i pos     ] := t;
                         swapped             := TRUE
                      FI
                 OD;
                 swapped
           DO SKIP OD;
           # now re-order adjacent numbers so they have the highest concatenated value #
           WHILE BOOL swapped := FALSE;
                 FOR i pos TO UPB result - 1 DO
                     STRING l := TOSTRING result[ i pos     ];
                     STRING r := TOSTRING result[ i pos + 1 ];
                     IF TOINT ( l + r ) < TOINT ( r + l ) THEN
                         INT t = result[ i pos + 1 ];
                         result[ i pos + 1 ] := result[ i pos ];
                         result[ i pos     ] := t;
                         swapped             := TRUE
                     FI
                 OD;
                 swapped
           DO SKIP OD;
           result
       FI # CONCATSORT # ;
    # prints the array a #
    OP PRINT = ( []INT a )VOID:
       FOR a pos FROM LWB a TO UPB a DO
            print( ( TOSTRING a[ a pos ] ) )
       OD # PRINT # ;

    # task test cases #
    PRINT CONCATSORT []INT( 1, 34, 3, 98, 9, 76, 45, 4 );
    print( ( newline ) );
    PRINT CONCATSORT []INT( 54, 546, 548, 60 );
    print( ( newline ) )

END


function write_array(a)
    io.write("[")
    for i=0,#a do
        if i>0 then
            io.write(", ")
        end
        io.write(tostring(a[i]))
    end
    io.write("]")
end

function kosaraju(g)
    -- 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    local size = #g

    local vis = {}
    for i=0,size do
        -- all false by default
        vis[i] = false
    end

    local l = {}
    for i=0,size do
        -- all zero by default
        l[i] = 0
    end

    local x = size+1  -- index for filling l in reverse order

    local t = {}    -- transpose graph

    -- Recursive subroutine 'visit'
    function visit(u)
        if not vis[u] then
            vis[u] = true
            for i=0,#g[u] do
                local v = g[u][i]
                visit(v)
                if t[v] then
                    local a = t[v]
                    a[#a+1] = u
                else
                    t[v] = {[0]=u}
                end
            end
            x = x - 1
            l[x] = u
        end
    end

    -- 2. For each vertex u of the graph do visit(u)
    for i=0,#g do
        visit(i)
    end
    local c = {}
    for i=0,size do
        -- used for component assignment
        c[i] = 0
    end

    -- Recursive subroutine 'assign'
    function assign(u, root)
        if vis[u] then  -- repurpose vis to mean 'unassigned'
            vis[u] = false
            c[u] = root
            for i=0,#t[u] do
                local v = t[u][i]
                assign(v, root)
            end
        end
    end

    -- 3: For each element u of l in order, do assign(u, u)
    for i=0,#l do
        local u = l[i]
        assign(u, u)
    end

    return c
end

-- main
local g = {
    [0]={[0]=1},
    [1]={[0]=2},
    [2]={[0]=0},
    [3]={[0]=1, [1]=2, [2]=4},
    [4]={[0]=3, [1]=5},
    [5]={[0]=2, [1]=6},
    [6]={[0]=5},
    [7]={[0]=4, [1]=6, [2]=7},
}

write_array(kosaraju(g))
print()


largestConcInt: function [arr]->
    max map permutate arr 's [
        to :integer join map s => [to :string]
    ]

loop [[1 34 3 98 9 76 45 4] [54 546 548 60]] 'a ->
    print largestConcInt a


LargestConcatenatedInts(var){
	StringReplace, var, A_LoopField,%A_Space%,, all
	Sort, var, D`, fConcSort
	StringReplace, var, var, `,,, all
	return var
}

ConcSort(a, b){
	m := a . b	, n := b . a
    return m < n ? 1 : m > n ? -1 : 0
}


function cmp(i1, v1, i2, v2, u1, u2) {
	u1 = v1""v2;
	u2 = v2""v1;
        return (u2 - u1)
}
function largest_int_from_concatenated_ints(X) {
 	PROCINFO["sorted_in"]="cmp";
	u="";
	for (i in X) u=u""X[i];
	return u
}

BEGIN {
	split("1 34 3 98 9 76 45 4",X);
	print largest_int_from_concatenated_ints(X)

	split("54 546 548 60",X);
	print largest_int_from_concatenated_ints(X)
}


type
  Vertex = int
  Graph = seq[seq[Vertex]]
  Scc = seq[Vertex]

func korasaju(g: Graph): seq[Scc] =

  var
    size = g.len
    visited = newSeq[bool](size)        # All false by default.
    l = newSeq[Vertex](size)            # All zero by default.
    x = size                            # Index for filling "l" in reverse order.
    t = newSeq[seq[Vertex]](size)       # Transposed graph.
    c = newSeq[Vertex](size)            # Used for component assignment.

  func visit(u: Vertex) =
    if not visited[u]:
      visited[u] = true
      for v in g[u]:
        visit(v)
        t[v].add(u)   # Construct transposed graph.
      dec x
      l[x] = u

  func assign(u, root: Vertex) =
    if visited[u]:
      # Repurpose visited to mean 'unassigned'.
      visited[u] = false
      c[u] = root
      for v in t[u]: v.assign(root)

  for u in 0..g.high: u.visit()
  for u in l: u.assign(u)

  # Build list of strongly connected components.
  var prev = -1
  for v1, v2 in c:
    if v2 != prev:
      prev = v2
      result.add @[]
    result[^1].add v1

when isMainModule:
  let g = @[@[1], @[2], @[0], @[1, 2, 4], @[3, 5], @[2, 6], @[5], @[4, 6, 7]]
  for scc in korasaju(g): echo $scc


use strict;
use warnings;
use feature 'say';

sub kosaraju {
    our(%k) = @_;
    our %g = ();
    our %h;
    my $i = 0;
    $g{$_}     = $i++ for sort keys %k;
    $h{$g{$_}} = $_   for      keys %g; # invert

    our(%visited, @stack, @transpose, @connected);
    sub visit {
        my($u) = @_;
        unless ($visited{$u}) {
            $visited{$u} = 1;
            for my $v (@{$k{$u}}) {
                visit($v);
                push @{$transpose[$g{$v}]}, $u;
            }
            push @stack, $u;
        }
    }

    sub assign {
        my($u, $root) = @_;
        if ($visited{$u}) {
            $visited{$u} = 0;
            $connected[$g{$u}] = $root;
            assign($_, $root) for @{$transpose[$g{$u}]};
        }
    }

    visit($_) for sort keys %g;
    assign($_, $_) for reverse @stack;

    my %groups;
    for my $i (0..$#connected) {
        my $id = $g{$connected[$i]};
        push @{$groups{$id}}, $h{$i};
    }
    say join ' ', @{$groups{$_}} for sort keys %groups;
}

my %test1 = (
    0 => [1],
    1 => [2],
    2 => [0],
    3 => [1, 2, 4],
    4 => [3, 5],
    5 => [2, 6],
    6 => [5],
    7 => [4, 6, 7]
);

my %test2 = (
   'Andy' => ['Bart'],
   'Bart' => ['Carl'],
   'Carl' => ['Andy'],
   'Dave' => [<Bart Carl Earl>],
   'Earl' => [<Dave Fred>],
   'Fred' => [<Carl Gary>],
   'Gary' => ['Fred'],
   'Hank' => [<Earl Gary Hank>]
);

kosaraju(%test1);
say '';
kosaraju(%test2);


      DIM Nums%(10)
      Nums%()=1,34,3,98,9,76,45,4
      PRINT FNlargestint(8)
      Nums%()=54,546,548,60
      PRINT FNlargestint(4)
      END

      DEF FNlargestint(len%)
      LOCAL i%,l$,a$,b$,sorted%
      REPEAT
        sorted%=TRUE
        FOR i%=0 TO len%-2
          a$=STR$Nums%(i%)
          b$=STR$Nums%(i%+1)
          IF a$+b$<b$+a$ SWAP Nums%(i%),Nums%(i%+1):sorted%=FALSE
        NEXT
      UNTIL sorted%
      FOR i%=0 TO len%-1
        l$+=STR$Nums%(i%)
      NEXT
      =l$


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int catcmp(const void *a, const void *b)
{
	char ab[32], ba[32];
	sprintf(ab, "%d%d", *(int*)a, *(int*)b);
	sprintf(ba, "%d%d", *(int*)b, *(int*)a);
	return strcmp(ba, ab);
}

void maxcat(int *a, int len)
{
	int i;
	qsort(a, len, sizeof(int), catcmp);
	for (i = 0; i < len; i++)
		printf("%d", a[i]);
	putchar('\n');
}

int main(void)
{
	int x[] = {1, 34, 3, 98, 9, 76, 45, 4};
	int y[] = {54, 546, 548, 60};

	maxcat(x, sizeof(x)/sizeof(x[0]));
	maxcat(y, sizeof(y)/sizeof(y[0]));

	return 0;
}


with javascript_semantics

sequence visited, l, t, c

procedure visit(sequence g, integer u)
    if not visited[u] then
        visited[u] = true
        for i=1 to length(g[u]) do
            integer v = g[u][i]
            visit(g,v)
            t[v] = deep_copy(t[v]) & u
        end for
        l &= u
    end if
end procedure

procedure assign(integer u, root=u)
    if visited[u] then
        visited[u] = false
        c[u] = root
        for v=1 to length(t[u]) do
            assign(t[u][v], root)
        end for
    end if
end procedure

function korasaju(sequence g)
    integer len = length(g)
    visited = repeat(false,len)
    l = {}
    t = repeat({},len)
    for u=1 to len do
        visit(g,u)
    end for
    c = repeat(0,len)
    for u=length(l) to 1 by -1 do
        assign(l[u])
    end for
    return c
end function

constant g = {{2}, {3}, {1}, {2, 3, 5}, {4, 6}, {3, 7}, {6}, {5, 7, 8}}
?korasaju(g)


def kosaraju(g):
    class nonlocal: pass

    # 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    size = len(g)

    vis = [False]*size # vertexes that have been visited
    l = [0]*size
    nonlocal.x = size
    t = [[]]*size   # transpose graph

    def visit(u):
        if not vis[u]:
            vis[u] = True
            for v in g[u]:
                visit(v)
                t[v] = t[v] + [u]
            nonlocal.x = nonlocal.x - 1
            l[nonlocal.x] = u

    # 2. For each vertex u of the graph do visit(u)
    for u in range(len(g)):
        visit(u)
    c = [0]*size

    def assign(u, root):
        if vis[u]:
            vis[u] = False
            c[u] = root
            for v in t[u]:
                assign(v, root)

    # 3: For each element u of l in order, do assign(u, u)
    for u in l:
        assign(u, u)

    return c

g = [[1], [2], [0], [1,2,4], [3,5], [2,6], [5], [4,6,7]]
print kosaraju(g)


using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var source1 = new int[] { 1, 34, 3, 98, 9, 76, 45, 4 };
        var source2 = new int[] { 54, 546, 548, 60 };

        var largest1 = LargestPossibleSequence(source1);
        var largest2 = LargestPossibleSequence(source2);

        Console.WriteLine("The largest possible integer from set 1 is: {0}", largest1);
        Console.WriteLine("The largest possible integer from set 2 is: {0}", largest2);
    }

    static long LargestPossibleSequence(int[] ints)
    {
        return long.Parse(string.Join("", ints.OrderBy(i => i, new IntConcatenationComparer()).Reverse()));
    }
}

class IntConcatenationComparer : IComparer<int>
{
    public int Compare(int x, int y)
    {
        var xy = int.Parse(x.ToString() + y.ToString());
        var yx = int.Parse(y.ToString() + x.ToString());

        return xy - yx;
    }
}


#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <string>

std::string findLargestConcat ( std::vector< int > & mynumbers ) {
   std::vector<std::string> concatnumbers ;
   std::sort ( mynumbers.begin( ) , mynumbers.end( ) ) ;
   do {
      std::ostringstream numberstream ;
      for ( int i : mynumbers )
	 numberstream << i ;
      concatnumbers.push_back( numberstream.str( ) ) ;
   } while ( std::next_permutation( mynumbers.begin( ) ,
	    mynumbers.end( ) )) ;
   return *( std::max_element( concatnumbers.begin( ) ,
	 concatnumbers.end( ) ) ) ;
}

int main( ) {
   std::vector<int> mynumbers = { 98, 76 , 45 , 34, 9 , 4 , 3 , 1 } ;
   std::vector<int> othernumbers = { 54 , 546 , 548 , 60 } ;
   std::cout << "The largest concatenated int is " <<
      findLargestConcat( mynumbers ) << " !\n" ;
   std::cout << "And here it is " << findLargestConcat( othernumbers )
      << " !\n" ;
   return 0 ;
}


#lang racket

(require racket/dict)

;; G is a dictionary of vertex -> (list vertex)
(define (Kosuraju G)
  (letrec
      ((vertices (remove-duplicates (append (dict-keys G) (append* (dict-values G)))))
       (visited?-dict (make-hash)) ; or any mutable dict type
       (assigned-dict (make-hash)) ; or any mutable dict type
       (neighbours:in (λ (u) (for/list (([v outs] (in-dict G)) #:when (member u outs)) v)))
       (visit! (λ (u L)
                 (cond [(dict-ref visited?-dict u #f) L]
                       [else (dict-set! visited?-dict u #t)
                             (cons u (for/fold ((L L)) ((v (in-list (dict-ref G u)))) (visit! v L)))])))
       (assign! (λ (u root)
                  (unless (dict-ref assigned-dict u #f)
                    (dict-set! assigned-dict u root)
                    (for ((v (in-list (neighbours:in u)))) (assign! v root)))))
       (L (for/fold ((l null)) ((u (in-dict-keys G))) (visit! u l))))

    (for ((u (in-list L))) (assign! u u))
    (map (curry map car) (group-by cdr (dict->list assigned-dict) =))))

(module+ test
  (Kosuraju '((0 1)
              (2 0)
              (5 2 6)
              (6 5)
              (1 2)
              (3 1 2 4) ; equvalent to (3 . (1 2 4))
              (4 5 3)
              (7 4 7 6))))


sub kosaraju (%k) {
    my %g = %k.keys.sort Z=> flat ^%k;
    my %h = %g.invert;
    my %visited;
    my @stack;
    my @transpose;
    my @connected;

    sub visit ($u) {
        unless %visited{$u} {
            %visited{$u} = True;
            for |%k{$u} -> $v {
                visit($v);
                @transpose[%g{$v}].push: $u;
            }
            @stack.push: $u;
        }
    }

    sub assign ($u, $root) {
        if %visited{$u} {
            %visited{$u}   = False;
            @connected[%g{$u}] = $root;
            assign($_, $root) for |@transpose[%g{$u}];
        }
    }

    .&visit for %g.keys;
    assign($_, $_) for @stack.reverse;

    (|%g{@connected}).pairs.categorize( *.value, :as(*.key) ).values.map: { %h{|$_} };
}

# TESTING

-> $test { say "\nStrongly connected components: ", |kosaraju($test).sort } for

# Same test data as all other entries, converted to a hash of lists
(((1),(2),(0),(1,2,4),(3,5),(2,6),(5),(4,6,7)).pairs.hash),

# Same layout test data with named vertices instead of numbered.
(
 %(:Andy<Bart>,
   :Bart<Carl>,
   :Carl<Andy>,
   :Dave<Bart Carl Earl>,
   :Earl<Dave Fred>,
   :Fred<Carl Gary>,
   :Gary<Fred>,
   :Hank<Earl Gary Hank>)
)


shared void run() {

	function comparator(Integer x, Integer y) {
		assert (is Integer xy = Integer.parse(x.string + y.string),
			is Integer yx = Integer.parse(y.string + x.string));
		return yx <=> xy;
	}

	function biggestConcatenation({Integer*} ints) => "".join(ints.sort(comparator));

	value test1 = {1, 34, 3, 98, 9, 76, 45, 4};
	print(biggestConcatenation(test1));

	value test2 = {54, 546, 548, 60};
	print(biggestConcatenation(test2));
}


(defn maxcat [coll]
  (read-string
    (apply str
           (sort (fn [x y]
                   (apply compare
                          (map read-string [(str y x) (str x y)])))
                 coll))))

(prn (map maxcat [[1 34 3 98 9 76 45 4] [54 546 548 60]]))


(defun int-concat (ints)
  (read-from-string (format nil "~{~a~}" ints)))

(defun by-biggest-result (first second)
  (> (int-concat  (list first second)) (int-concat (list second first))))

(defun make-largest-int (ints)
  (int-concat (sort ints #'by-biggest-result)))


func korasaju(Array g) {
    # 1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
    var vis = g.len.of(false)
    var L   = []
    var x   = g.end
    var t   = g.len.of { [] }

    # Recursive
    func visit(u) {
        if (!vis[u]) {
            vis[u] = true
            g[u].each {|v|
                visit(v)
                t[v] << u
            }
            L[x--] = u
        }
    }

    # 2. For each vertex u of the graph do visit(u)
    g.range.each {|u|
        visit(u)
    }

    var c = []

    # 3. Recursive subroutine:
    func assign(u, root) {
        if (vis[u]) {
            vis[u] = false
            c[u] = root
            t[u].each {|v|
                assign(v, root)
            }
        }
    }

    # 3. For each element u of L in order, do assign(u, u)
    L.each {|u|
        assign(u, u)
    }

    return c
}

var g = [[1], [2], [0], [1, 2, 4], [3, 5], [2, 6], [5], [4, 6, 7]]
say korasaju(g)


datatype 'a node = Node of 'a * bool ref * 'a node list ref * 'a node list ref

fun node x = Node (x, ref false, ref nil, ref nil)
fun mark (Node (_, r, _, _)) = !r before r := true
fun unmark (Node (_, r, _, _)) = !r before r := false

fun value (Node (x, _, _, _)) = x
fun sources (Node (_, _, ref xs, _)) = xs
fun targets (Node (_, _, _, ref ys)) = ys

fun connect (m, n) =
  let
    val Node (_, _, _, ns) = m
    val Node (_, _, ms, _) = n
  in
    ms := m :: !ms;
    ns := n :: !ns
  end

datatype 'a step = One of 'a | Many of 'a list

fun visit (ms, nil) = ms
  | visit (ms, One m :: ss) = visit (m :: ms, ss)
  | visit (ms, Many nil :: ss) = visit (ms, ss)
  | visit (ms, Many (n :: ns) :: ss) =
    if mark n then
      visit (ms, Many ns :: ss)
    else
      visit (ms, Many (targets n) :: One n :: Many ns :: ss)

fun assign (xs, nil) = xs
  | assign (xs, nil :: ss) = assign (xs, ss)
  | assign (xs, (n :: ns) :: ss) =
    if unmark n then
      assign (value n :: xs, sources n :: ns :: ss)
    else
      assign (xs, ns :: ss)

fun assigns (xs, nil) = xs
  | assigns (xs, n :: ns) =
    if unmark n then
      let
        val x = sources n :: nil
        val x = value n :: assign (nil, x)
      in
        assigns (x :: xs, ns)
      end
    else
      assigns (xs, ns)

fun kosaraju xs = assigns (nil, visit (nil, Many xs :: nil))

fun make (n, is, ijs) =
  let
    val xs = Vector.tabulate (n, node)
    fun item i = Vector.sub (xs, i)
    fun step (i, j) = connect (item i, item j)
    fun path (i :: j :: js) = (step (i, j); path (j :: js))
      | path _ = ()
  in
    map item is before app path ijs
  end

val is = 0 :: nil
val ijs =
  [0, 1, 2, 0, 3, 4, 0, 5, 7] ::
  [0, 9, 10, 11, 12, 9, 11] ::
  [1, 12] ::
  [3, 5, 6, 7, 8, 6, 15] ::
  [5, 13, 14, 13, 15] ::
  [8, 15] ::
  [10, 13] ::
  nil

val ns = make (16, is, ijs)
val xs = kosaraju ns


func kosaraju(graph: [[Int]]) -> [Int] {
  let size = graph.count
  var x = size
  var vis = [Bool](repeating: false, count: size)
  var l = [Int](repeating: 0, count: size)
  var c = [Int](repeating: 0, count: size)
  var t = [[Int]](repeating: [], count: size)

  func visit(_ u: Int) {
    guard !vis[u] else {
      return
    }

    vis[u] = true

    for v in graph[u] {
      visit(v)
      t[v].append(u)
    }

    x -= 1
    l[x] = u
  }

  for u in 0..<graph.count {
    visit(u)
  }

  func assign(_ u: Int, root: Int) {
    guard vis[u] else {
      return
    }

    vis[u] = false
    c[u] = root

    for v in t[u] {
      assign(v, root: root)
    }
  }

  for u in l {
    assign(u, root: u)
  }

  return c
}

let graph = [
  [1],
  [2],
  [0],
  [1, 2, 4],
  [3, 5],
  [2, 6],
  [5],
  [4, 6, 7]
]

print(kosaraju(graph: graph))


import std.stdio, std.algorithm, std.conv, std.array, permutations2;

auto maxCat1(in int[] arr) pure @safe {
    return arr.to!(string[]).permutations.map!join.reduce!max;
}

auto maxCat2(in int[] arr) pure nothrow @safe {
    return arr.to!(string[]).sort!q{b ~ a < a ~ b}.join;
}

auto maxCat3(in int[] arr) /*pure nothrow @safe*/ {
    immutable maxL = arr.reduce!max.text.length;
    return arr.to!(string[])
           .schwartzSort!(s => s.replicate(maxL/s.length + 1), "a > b")
           .join;
}

void main() {
    const lists = [[1, 34, 3, 98, 9, 76, 45, 4], [54, 546, 548, 60]];
    [&maxCat1, &maxCat2, &maxCat3].map!(cat => lists.map!cat).writeln;
}


defmodule RC do
  def largest_int(list) do
    sorted = Enum.sort(list, fn x,y -> "#{x}#{y}" >= "#{y}#{x}" end)
    Enum.join(sorted)
  end
end

IO.inspect RC.largest_int [1, 34, 3, 98, 9, 76, 45, 4]
IO.inspect RC.largest_int [54, 546, 548, 60]


Module Module1

    Function Kosaraju(g As List(Of List(Of Integer))) As List(Of Integer)
        Dim size = g.Count
        Dim vis(size - 1) As Boolean
        Dim l(size - 1) As Integer
        Dim x = size

        Dim t As New List(Of List(Of Integer))
        For i = 1 To size
            t.Add(New List(Of Integer))
        Next

        Dim visit As Action(Of Integer) = Sub(u As Integer)
                                              If Not vis(u) Then
                                                  vis(u) = True
                                                  For Each v In g(u)
                                                      visit(v)
                                                      t(v).Add(u)
                                                  Next
                                                  x -= 1
                                                  l(x) = u
                                              End If
                                          End Sub

        For i = 1 To size
            visit(i - 1)
        Next
        Dim c(size - 1) As Integer

        Dim assign As Action(Of Integer, Integer) = Sub(u As Integer, root As Integer)
                                                        If vis(u) Then
                                                            vis(u) = False
                                                            c(u) = root
                                                            For Each v In t(u)
                                                                assign(v, root)
                                                            Next
                                                        End If
                                                    End Sub

        For Each u In l
            assign(u, u)
        Next

        Return c.ToList
    End Function

    Sub Main()
        Dim g = New List(Of List(Of Integer)) From {
            New List(Of Integer) From {1},
            New List(Of Integer) From {2},
            New List(Of Integer) From {0},
            New List(Of Integer) From {1, 2, 4},
            New List(Of Integer) From {3, 5},
            New List(Of Integer) From {2, 6},
            New List(Of Integer) From {5},
            New List(Of Integer) From {4, 6, 7}
        }

        Dim output = Kosaraju(g)
        Console.WriteLine("[{0}]", String.Join(", ", output))
    End Sub

End Module


var kosaraju = Fn.new { |g|
    var gc = g.count
    // 1. For each vertex u of the graph, mark u as unvisited. Let l be empty.
    var vis = List.filled(gc, false)
    var l = List.filled(gc, 0)
    var x = gc                     // index for filling l in reverse order
    var t = List.filled(gc, null)  // transpose graph
    for (i in 0...gc) t[i] = []
    var visit // recursive function
    visit = Fn.new { |u|
        if (!vis[u]) {
            vis[u] = true
            for (v in g[u]) {
                visit.call(v)
                t[v].add(u)  // construct transpose
            }
            x = x - 1
            l[x] = u
        }
    }
    // 2. For each vertex u of the graph do visit.call(u).
    for (i in 0...gc) visit.call(i)
    var c = List.filled(gc, 0) // result, the component assignment
    var assign // recursive function
    assign = Fn.new { |u, root|
        if (vis[u]) {  // repurpose vis to mean 'unassigned'
            vis[u] = false
            c[u] = root
            for (v in t[u]) assign.call(v, root)
        }
    }
    // 3: For each element u of l in order, do assign.call(u,u).
    for (u in l) assign.call(u, u)
    return c
}

var g = [ [1], [2], [0], [1, 2, 4], [3, 5], [2, 6], [5], [4, 6, 7] ]
System.print(kosaraju.call(g))


-module( largest_int_from_concatenated ).

-export( [ints/1, task/0] ).

ints( Ints ) ->
	Int_strings = [erlang:integer_to_list(X) || X <- Ints],
	Pad_ints = [{X ++ X, X} || X <- Int_strings],
	erlang:list_to_integer( lists:append([Int || {_Pad, Int} <- lists:reverse(lists:sort(Pad_ints))]) ).

task() ->
	[io:fwrite("Largest ~p from ~p~n", [ints(X), X]) || X <- [[1, 34, 3, 98, 9, 76, 45, 4], [54, 546, 548, 60]]].


// Form largest integer which is a permutation from a list of integers. Nigel Galloway: March 21st., 2018
let fN g = List.map (string) g |> List.sortWith(fun n g->if n+g<g+n then 1 else -1) |> System.String.Concat


const VISITED=0,ASSIGNED=1;

fcn visit(u,G,L){	// u is ((visited,assigned), (id,edges))
   u0:=u[0];
   if(u0[VISITED]) return();
   u0[VISITED]=True;
   foreach idx in (u[1][1,*]){ visit(G[idx],G,L) } // vist out-neighbours
   L.insert(0,u);	// prepend u to L
}
fcn assign(u,root,G){  // u as above, root is a list of strong components
   u0:=u[0];
   if(u0[ASSIGNED]) return();
   root.append(u[1][0]);
   u0[ASSIGNED]=True;
   uid:=u[1][0];
   foreach v in (G){  // traverse graph to find in-neighbours, fugly
      n,ins := v[1][0],v[1][1,*];
      if(ins.holds(uid)) assign(G[n],root,G); // assign in-neighbour
   }
}
fcn kosaraju(graph){  // Use Tarjan's algorithm instead of this one
   // input: graph G = (V, Es)
   // output: set of strongly connected components (sets of vertices)

   // convert graph to ( (index,lowlink,onStack),(id,links)), ...)
   // sorted by id
   G:=List.createLong(graph.len(),0);
   foreach v in (graph){ G[v[0]]=T( List(False,False),v) }

   L:=List();
   foreach u in (G){ visit(u,G,L) }

   components:=List.createLong(graph.len(),List.copy,True);
   foreach u in (L){ assign(u,components[u[1][0]],G) }
   components=components.filter();

   println("List of strongly connected components:");
   foreach c in (components){ println(c.reverse().concat(",")) }

   return(components);
}


USING: assocs io kernel math qw sequences sorting ;
IN: rosetta-code.largest-int

: pad ( target seq -- padded )
    2dup length / swap <repetition> concat swap head ;

: largest-int ( seq -- )
    dup dup [ length ] map supremum    ! find longest length so we know how much to pad
    [ swap pad ] curry map             ! pad the integers
    <enum> sort-values                 ! sort the padded integers
    keys                               ! find the original indices of the sorted integers
    swap nths                          ! order non-padded integers according to their sorted order
    reverse concat print ;

qw{ 1 34 3 98 9 76 45 4 } qw{ 54 546 548 60 } [ largest-int ] [email protected]


      SUBROUTINE SWAP(A,B)	!Why can't the compiler supply these!
       INTEGER A,B,T
        T = B
        B = A
        A = T
      END

      SUBROUTINE BIGUP(TEXT,N)	!Outputs the numbers in TEXT to give the biggest number.
       CHARACTER*(*) TEXT(*)	!The numbers as text, aligned left.
       INTEGER N		!The number of them.
       INTEGER XLAT(N),L(N)	!An index and a set of lengths.
       INTEGER I,J,M		!Assorted steppers.
       INTEGER TI,TJ		!Fingers to a text.
       INTEGER LI,LJ		!Lengths of the fingered texts.
       INTEGER MSG		!I/O unit number.
       COMMON /IODEV/ MSG	!Old style.
        DO I = 1,N	!Step through my supply of texts.
          XLAT(I) = I		!Preparing a finger to them.
          L(I) = LEN_TRIM(TEXT(I))	!And noting their last non-blank.
        END DO		!On to the next.
        WRITE (MSG,1) "Supplied",(TEXT(I)(1:L(I)), I = 1,N)	!Show the grist.
    1   FORMAT (A12,":",<N>(A,","))	!Instead of <N>, 666 might suffice.
Crude bubblesort. No attempt at noting the bounds of swaps made.
        DO M = N,1,-1	!Just for fun, go backwards.
          DO I = 2,M		!Start a scan.
            J = I - 1		!Comparing element I to element I - 1.
            TI = XLAT(I)	!Thus finger the I'th text in XLAT order.
            TJ = XLAT(J)	!And its supposed predecessor.
            LI = L(TI)		!The length of the fingered text.
            LJ = L(TJ)		!All this to save on typing below.
            IF (LI .EQ. LJ) THEN	!If the texts are equal lengths,
              IF (TEXT(TI).LT.TEXT(TJ)) CALL SWAP(XLAT(I),XLAT(J))	!A simple comparison.
             ELSE	!But if not, construct the actual candidate texts for comparison.
              IF (TEXT(TI)(1:LI)//TEXT(TJ)(1:LJ)	!These two will be the same length.
     1        .LT.TEXT(TJ)(1:LJ)//TEXT(TI)(1:LI))	!Just as above.
     2        CALL SWAP(XLAT(I),XLAT(J))	!J shall now follow I.
            END IF			!So much for that comparison.
          END DO		!On to the next.
        END DO	!The original plan was to reveal element XLAT(M) as found.
        WRITE (MSG,2) "Biggest",(TEXT(XLAT(I))(1:L(XLAT(I))),I = N,1,-1)	!But, all at once is good too.
    2   FORMAT (A12,":",<N>(A," "))	!The space maintains identity.
      END	!That was fun.

      PROGRAM POKE
      CHARACTER*4 T1(10)	!Prepare some example arrays.
      CHARACTER*4 T2(4)		!To hold the specified examples.
      INTEGER MSG
      COMMON /IODEV/ MSG
      DATA T1(1:8)/"1","34","3","98","9","76","45","4"/
      DATA T2/"54","546","548","60"/
      MSG = 6		!Standard output.
      WRITE (MSG,1)
    1 FORMAT ("Takes a list of integers and concatenates them so as ",
     1 "to produce the biggest possible number.",/,
     2 "The result is shown with spaces between the parts ",
     3 "to show provenance. Ignore them otherwise."/)
      CALL BIGUP(T1,8)

      WRITE (MSG,*)
      CALL BIGUP(T2,4)

      WRITE (MSG,*) "These are supplied in lexicographical order..."
      CALL BIGUP((/"5","54"/),2)

      WRITE (MSG,*) "But this is not necessarily the biggest order."
      CALL BIGUP((/"5","56"/),2)

      WRITE (MSG,*) "And for those who count..."
      DO I = 1,10
        WRITE (T1(I),"(I0)") I	!This format code produces only the necessary text.
      END DO			!Thus, the numbers are aligned left in the text field.
      CALL BIGUP(T1,10)
      END


#define MAXDIGITS 8

function catint( a as string, b as string ) as uinteger
    return valint(a+b)
end function

function grt( a as string, b as string ) as boolean
    return catint(a, b)>catint(b, a)
end function

sub shellsort( a() as string )
    'quick and dirty shellsort, not the focus of this exercise
    dim as uinteger gap = ubound(a), i, j, n=ubound(a)
    dim as string temp
    do
        gap = int(gap / 2.2)
        for i=gap to n
            temp = a(i)
            j=i
            while j>=gap andalso grt( a(j-gap), temp )
                a(j) = a(j - gap)
                j -= gap
            wend
            a(j) = temp
        next i
    loop until gap = 1
end sub

sub sort_and_print( a() as string )
    dim as uinteger i
    dim as string outstring = ""
    shellsort(a())
    for i=0 to ubound(a)
        outstring = a(i)+outstring
    next i
    print outstring
end sub

dim as string set1(8) = {"1", "34", "3", "98", "9", "76", "45", "4"}
dim as string set2(4) = {"54", "546", "548", "60"}

sort_and_print(set1())
sort_and_print(set2())


'Largest int from concatenated ints

Public Sub Main()
Dim iList1 As Integer[] = [1, 34, 3, 98, 9, 76, 45, 4]      'Integer list 1
Dim iList2 As Integer[] = [54, 546, 548, 60]                'Integer list 2

Calc(iList1)                                                'Send List 1 to Calc routine
Calc(iList2)                                                'Send List 2 to Calc routine

End
'_________________________________________________________________________________________

Public Sub Calc(iList As Integer[])
Dim siCount1, siCount2, siCounter As Short                  'Counters
Dim sList As New String[]                                   'To hold converted integers
Dim bTrigger As Boolean                                     'To trigger a found match

For Each siCount1 In iList                                  'For each integer in the list..
  sList.Add(Str(siCount1))                                  'Convert to a string and add to sList
  If Len(Str(siCount1)) > siCounter Then                    'If the length of the string is greater than siCounter then..
    siCounter = Len(Str(siCount1))                          'siCounter = length of the string
  End If
Next

For siCount1 = 0 To sList.Max                               'For each item in sList
  If Len(sList[siCount1]) < siCounter Then                  'If the length of the string is less that siCounter then..
    sList[siCount1] &= Right(sList[siCount1], 1)            'Add the same digit to the string e.g. in list 1 "9" becomes "99", list 2 "54" becomes "544"
  End If
Next

sList.Sort(gb.Descent)                                      'Sort the list in decending order

For siCount1 = 0 To sList.Max                               'For each item in sList
  bTrigger = False                                          'Set bTrigger to False
  For siCount2 = 0 To iList.Max                             'Loop through each item in iList
    If Val(sList[siCount1]) = iList[siCount2] Then          'If the value of each is the same e.g. "98" = 98 then
      bTrigger = True                                       'Set bTrigger to True
      Continue                                              'Exit the loop
    Endif
  Next
  If Not bTrigger Then                                      'If there was no match e.g. there is no "99" then..
    sList[siCount1] = Left(sList[siCount1], siCounter - 1)  'Strip out the end digit e.g. "99" becomes 9 again
  End If
Next

Print Val(sList.Join(""))                                   'Join all items in sList together and print

End


// Variation of method 3.  Repeat digits to at least the size of the longest,
// then sort as strings.
package main

import (
    "fmt"
    "math/big"
    "sort"
    "strconv"
    "strings"
)

type c struct {
    i     int
    s, rs string
}

type cc []*c

func (c cc) Len() int           { return len(c) }
func (c cc) Less(i, j int) bool { return c[j].rs < c[i].rs }
func (c cc) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }

// Function required by task.  Takes a list of integers, returns big int.
func li(is ...int) *big.Int {
    ps := make(cc, len(is))
    ss := make([]c, len(is))
    ml := 0
    for j, i := range is {
        p := &ss[j]
        ps[j] = p
        p.i = i
        p.s = strconv.Itoa(i)
        if len(p.s) > ml {
            ml = len(p.s)
        }
    }
    for _, p := range ps {
        p.rs = strings.Repeat(p.s, (ml+len(p.s)-1)/len(p.s))
    }
    sort.Sort(ps)
    s := make([]string, len(ps))
    for i, p := range ps {
        s[i] = p.s
    }
    b, _ := new(big.Int).SetString(strings.Join(s, ""), 10)
    return b
}

func main() {
    fmt.Println(li(1, 34, 3, 98, 9, 76, 45, 4))
    fmt.Println(li(54, 546, 548, 60))
}


def largestInt = { c -> c.sort { v2, v1 -> "$v1$v2" <=> "$v2$v1" }.join('') as BigInteger }


import Data.List (sortBy)
import Data.Ord (comparing)

main = print (map maxcat [[1,34,3,98,9,76,45,4], [54,546,548,60]] :: [Integer])
    where
      sorted xs = let pad x  = concat $ replicate (maxLen `div` length x + 1) x
                      maxLen = maximum $ map length xs
                  in  sortBy (flip $ comparing pad) xs

      maxcat = read . concat . sorted . map show


import Collections    # For the Heap (dense priority queue) class

procedure main(a)
    write(lici(a))
end

procedure lici(a)
    every (result := "") ||:= Heap(a,,cmp).gen()
    return result
end

procedure cmp(a,b)
   return (a||b) > (b||a)
end


import java.util.*;

public class IntConcat {

    private static Comparator<Integer> sorter = new Comparator<Integer>(){
        @Override
        public int compare(Integer o1, Integer o2){
            String o1s = o1.toString();
            String o2s = o2.toString();

            if(o1s.length() == o2s.length()){
                return o2s.compareTo(o1s);
            }

            int mlen = Math.max(o1s.length(), o2s.length());
            while(o1s.length() < mlen * 2) o1s += o1s;
            while(o2s.length() < mlen * 2) o2s += o2s;

            return o2s.compareTo(o1s);
        }
    };

    public static String join(List<?> things){
        String output = "";
        for(Object obj:things){
            output += obj;
        }
        return output;
    }

    public static void main(String[] args){
        List<Integer> ints1 = new ArrayList<Integer>(Arrays.asList(1, 34, 3, 98, 9, 76, 45, 4));

        Collections.sort(ints1, sorter);
        System.out.println(join(ints1));

        List<Integer> ints2 = new ArrayList<Integer>(Arrays.asList(54, 546, 548, 60));

        Collections.sort(ints2, sorter);
        System.out.println(join(ints2));
    }
}


 (function () {
     'use strict';

     // maxCombine :: [Int] -> Int
     function maxCombine(xs) {
         return parseInt(
             xs.sort(
                 function (x, y) {
                     var a = x.toString(),
                         b = y.toString(),
                         ab = parseInt(a + b),
                         ba = parseInt(b + a);

                     return ab > ba ? -1 : (ab < ba ? 1 : 0);
                 }
             )
             .join(''), 10
         );
     }

     return [
        [1, 34, 3, 98, 9, 76, 45, 4],
        [54, 546, 548, 60]
     ].map(maxCombine);

 })();


def largest_int:

  def pad(n):  . + (n - length) * .[length-1:];

  map(tostring)
  | (map(length) | max) as $max
  | map([., pad($max)])
  | sort_by( .[1] )
  | map( .[0] ) | reverse | join("") ;

# Examples:
([1, 34, 3, 98, 9, 76, 45, 4],
 [54, 546, 548, 60])  | largest_int


function maxconcat(arr::Vector{<:Integer})
    b = sort(string.(arr); lt=(x, y) -> x * y < y * x, rev=true) |> join
    return try parse(Int, b) catch parse(BigInt, b) end
end

tests = ([1, 34, 3, 98, 9, 76, 45, 4],
         [54, 546, 548, 60],
         [1, 34, 3, 98, 9, 76, 45, 4, 54, 546, 548, 60])

for arr in tests
    println("Max concatenating in $arr:\n -> ", maxconcat(arr))
end


import kotlin.Comparator

fun main(args: Array<String>) {
    val comparator = Comparator<Int> { x, y -> "$x$y".compareTo("$y$x") }

    fun findLargestSequence(array: IntArray): String {
        return array.sortedWith(comparator.reversed()).joinToString("") { it.toString() }
    }

    for (array in listOf(
        intArrayOf(1, 34, 3, 98, 9, 76, 45, 4),
        intArrayOf(54, 546, 548, 60),
    )) {
        println("%s -> %s".format(array.contentToString(), findLargestSequence(array)))
    }
}


function icsort(numbers)
	table.sort(numbers,function(x,y) return (x..y) > (y..x) end)
	return numbers
end

for _,numbers in pairs({{1, 34, 3, 98, 9, 76, 45, 4}, {54, 546, 548, 60}}) do
	print(('Numbers: {%s}\n  Largest integer: %s'):format(
		table.concat(numbers,","),table.concat(icsort(numbers))
	))
end


makeLargestInt[list_] := Module[{sortedlist},
  sortedlist = Sort[list, Order[ToString[#1] <> ToString[#2], ToString[#2] <> ToString[#1]] < 0 &];
  Map[ToString, sortedlist] // StringJoin // FromDigits
  ]
(* testing with two examples *)
makeLargestInt[{1, 34, 3, 98, 9, 76, 45, 4}]
makeLargestInt[{54, 546, 548, 60}]


(quote cons "" join) :s+
('string map (over over swap s+ 's+ dip <) sort "" join int) :fn

(1 34 3 98 9 76 45 4) fn puts!
(54 546 548 60) fn puts!


/* NetRexx */
options replace format comments java crossref symbols nobinary

runSample(arg)
return

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method largestInt(il) public static
  ri = ''
  wa = ''
  -- put the list into an indexed string
  wa[0] = il.words
  loop ww = 1 to wa[0]
    wa[ww] = il.word(ww)
    end ww

  -- order the list
  loop wx = 1 to wa[0] - 1
    loop wy = wx + 1 to wa[0]
      xx = wa[wx]
      yy = wa[wy]
      xy = xx || yy
      yx = yy || xx
      if xy < yx then do
        -- swap xx and yy
        wa[wx] = yy
        wa[wy] = xx
        end
      end wy
    end wx

  -- rebuild list from indexed string
  loop ww = 1 to wa[0]
    ri = ri wa[ww]
    end ww
  return ri.space(0) -- concatenate the list elements into a single numeric

-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
method runSample(arg) private static
  ints = [ -
    '1 34 3 98 9 76 45 4', -
    '54 546 548 60' -
    ]
  loop il over ints
    say largestInt(il).right(20) ':' il.space(1, ',')
    end il
  return


import algorithm, sequtils, strutils, sugar

proc maxNum(x: seq[int]): string =
  var c = x.mapIt($it)
  c.sort((x, y) => cmp(y&x, x&y))
  c.join()

echo maxNum(@[1, 34, 3, 98, 9, 76, 45, 4])
echo maxNum(@[54, 546, 548, 60])


let myCompare a b = compare (b ^ a) (a ^ b)
let icsort nums = String.concat "" (List.sort myCompare (List.map string_of_int nums))


: largestInt  map(#asString) sortWith(#[ 2dup + -rot swap + > ]) sum asInteger ;


const
  base    = 10;
  MaxDigitCnt = 11;
  source1 : array[0..7] of integer = (1, 34, 3, 98, 9, 76, 45, 4);
  source2 : array[0..3] of integer = (54,546,548,60);
  source3 : array[0..3] of integer = (60, 54,545454546,0);

type
  tdata = record
            datOrg,
            datMod : LongWord;
            datStrOrg       : string[MaxDigitCnt];
          end;
  tArrData = array of tData;

procedure DigitCount(var n: tdata);
begin
  with n do
    //InttoStr is very fast
    str(datOrg,datStrOrg);

end;

procedure InsertData(var n: tdata;data:LongWord);
begin
  n.datOrg := data;
  DigitCount(n);
end;

function FindMaxLen(const ArrData:tArrData): LongWord;
var
  cnt : longInt;
  res,t : LongWord;
begin
  res := 0;// 1 is minimum
  for cnt :=  High(ArrData) downto Low(ArrData) do
  begin
    t := length(ArrData[cnt].datStrOrg);
    IF res < t then
      res := t;
  end;
  FindMaxLen := res;
end;

procedure ExtendCount(var ArrData:tArrData;newLen: integer);
var
  cnt,
  i,k : integer;
begin
  For cnt := High(ArrData) downto Low(ArrData) do
    with ArrData[cnt] do
    begin
      datMod := datOrg;
      i := newlen-length(datStrOrg);
      k := 1;
      while i > 0 do
      begin
        datMod := datMod *Base+Ord(datStrOrg[k])-Ord('0');
        inc(k);
        IF k >length(datStrOrg) then
          k := 1;
        dec(i);
      end;
    end;
end;

procedure SortArrData(var ArrData:tArrData);
var
  i,
  j,idx : integer;
  tmpData : tData;
begin
  For i := High(ArrData) downto Low(ArrData)+1 do
  begin
    idx := i;
    j := i-1;
    For j := j downto Low(ArrData) do
      IF ArrData[idx].datMod < ArrData[j].datMod then
         idx := j;
    IF idx <> i then
    begin
      tmpData     := ArrData[idx];
      ArrData[idx]:= ArrData[i];
      ArrData[i]  := tmpData;
    end;
  end;
end;

procedure ArrDataOutput(const ArrData:tArrData);
var
  i,l : integer;
  s : AnsiString;
begin
{ the easy way
  For i := High(ArrData) downto Low(ArrData) do
    write(ArrData[i].datStrOrg);
  writeln;
  *}
  l := 0;
  For i := High(ArrData) downto Low(ArrData) do
    inc(l,length(ArrData[i].datStrOrg));
  setlength(s,l);
  l:= 1;
  For i := High(ArrData) downto Low(ArrData) do
    with ArrData[i] do
    begin
      move(datStrOrg[1],s[l],length(datStrOrg));
      inc(l,length(datStrOrg));
    end;
  writeln(s);
end;

procedure HighestInt(var  ArrData:tArrData);
begin
  ExtendCount(ArrData,FindMaxLen(ArrData));
  SortArrData(ArrData);
  ArrDataOutput(ArrData);
end;

var
  i : integer;
  tmpData : tArrData;
begin
  // Source1
  setlength(tmpData,length(source1));
  For i := low(tmpData) to high(tmpData) do
    InsertData(tmpData[i],source1[i]);
  HighestInt(tmpData);
  // Source2
  setlength(tmpData,length(source2));
  For i := low(tmpData) to high(tmpData) do
    InsertData(tmpData[i],source2[i]);
  HighestInt(tmpData);
  // Source3
  setlength(tmpData,length(source3));
  For i := low(tmpData) to high(tmpData) do
    InsertData(tmpData[i],source3[i]);
  HighestInt(tmpData);
end.


with javascript_semantics
function catcmp(string a, string b)
    return compare(b&a,a&b)
end function

function method2(sequence s)
    return join(custom_sort(catcmp,apply(s,sprint)),"")
end function

?method2({1,34,3,98,9,76,45,4})
?method2({54,546,548,60})


function maxnum($nums) {
    usort($nums,  function ($x, $y) { return strcmp("$y$x", "$x$y"); });
    return implode('', $nums);
}

echo maxnum(array(1, 34, 3, 98, 9, 76, 45, 4)), "\n";
echo maxnum(array(54, 546, 548, 60)), "\n";


s_perm1(L, Num) =>
  permutation(L,P),
  Num = [I.to_string() : I in P].flatten().to_integer().


/* Largest catenation of integers            16 October 2013 */
/* Sort using method 2, comparing pairs of adjacent integers. */

Largest: procedure options (main);
   declare s(*) char (20) varying controlled, n fixed binary;
   get (n);
   allocate s(n);
   get list (s);
   s = trim(s);
   put skip edit (s) (a, x(1));
   put skip list ('Largest integer=', Largest_integer());

largest_integer: procedure () returns (char(100) varying);
   declare sorted bit (1);
   declare (true value ('1'b), false value ('0'b)) bit (1);
   declare i fixed binary;
   declare temp character(20) varying;

   do until (sorted);
      sorted = true;
      do i = 1 to n-1;
         if char(s(i)) || char(s(i+1)) < char(s(i+1)) || char(s(i)) then
            do;
               temp = s(i); s(i) = s(i+1); s(i+1) = temp; sorted = false;
            end;
      end;
   end;
   return (string(s));
end largest_integer;
end Largest;


Function Get-LargestConcatenation ( [int[]]$Integers )
    {
    #  Get the length of the largest integer
    $Length = ( $Integers | Sort -Descending | Select -First 1 ).ToString().Length

    #  Convert to an array of strings,
    #  sort by each number repeated Length times and truncated to Length,
    #  and concatenate (join)
    $Concat = ( [string[]]$Integers | Sort { ( $_ * $Length ).Substring( 0, $Length ) } -Descending ) -join ''

    #  Convert to integer (upsizing type if needed)
    try           { $Integer = [ int32]$Concat }
    catch { try   { $Integer = [ int64]$Concat }
            catch { $Integer = [bigint]$Concat } }

    return $Integer
    }


largest_int_v1(In, Out) :-
	maplist(name, In, LC),
	aggregate(max(V), get_int(LC, V), Out).

get_int(LC, V) :-
	permutation(LC, P),
	append(P, LV),
	name(V, LV).


try:
    cmp     # Python 2 OK or NameError in Python 3
    def maxnum(x):
        return ''.join(sorted((str(n) for n in x),
                              cmp=lambda x,y:cmp(y+x, x+y)))
except NameError:
    # Python 3
    from functools import cmp_to_key
    def cmp(x, y):
        return -1 if x<y else ( 0 if x==y else 1)
    def maxnum(x):
        return ''.join(sorted((str(n) for n in x),
                              key=cmp_to_key(lambda x,y:cmp(y+x, x+y))))

for numbers in [(1, 34, 3, 98, 9, 76, 45, 4), (54, 546, 548, 60)]:
    print('Numbers: %r\n  Largest integer: %15s' % (numbers, maxnum(numbers)))


[ sortwith
    [ 2dup swap join
      dip join $< ]
  [] swap witheach join ] is largest-int ( [ --> $ )

$ '1 34 3 98 9 76 45 4' nest$ largest-int echo$ cr
$ '54 546 548 60' nest$ largest-int echo$


Largest_int_from_concat_ints <- function(vec){

  #recursive function for computing all permutations
  perm <- function(vec) {
    n <- length(vec)
    if (n == 1)
      return(vec)
    else {
      x <- NULL
      for (i in 1:n){
        x <- rbind(x, cbind(vec[i], perm(vec[-i])))
      }
      return(x)
    }
  }

  permutations <- perm(vec)
  concat <- as.numeric(apply(permutations, 1, paste, collapse = ""))
  return(max(concat))
}

#Verify
Largest_int_from_concat_ints(c(54, 546, 548, 60))
Largest_int_from_concat_ints(c(1, 34, 3, 98, 9, 76, 45, 4))
Largest_int_from_concat_ints(c(93, 4, 89, 21, 73))


Red []

foreach seq [[1 34 3 98 9 76 45 4] [54 546 548 60]] [
  print rejoin sort/compare seq function [a b] [ (rejoin [a b]) > rejoin [b a] ]
]


/*REXX program constructs the largest integer  from an integer list using concatenation.*/
@.=.;     @.1 =   1   34    3  98  9  76  45  4  /*the  1st  integer list to be used.   */
          @.2 =  54  546  548  60                /* "   2nd     "      "   "  "   "     */
          @.3 =   4   45   54   5                /* "   3rd     "      "   "  "   "     */
w=0                                              /* [↓]   process all the integer lists.*/
    do j=1  while @.j\==.;         z= space(@.j) /*keep truckin' until lists exhausted. */
    w=max(w, length(z) );          $=            /*obtain maximum width to align output.*/
        do  while z\='';  idx= 1;  big= norm(1)  /*keep examining the list  until  done.*/
          do k=2  to  words(z);    #= norm(k)    /*obtain an a number from the list.    */
          L= max(length(big), length(#) )        /*get the maximum length of the integer*/
          if left(#, L, left(#, 1) )   <<=   left(big, L, left(big, 1) )    then iterate
          big= #;                  idx= k        /*we found a new biggie (and the index)*/
          end   /*k*/                            /* [↑]  find max concatenated integer. */
        z= delword(z, idx, 1)                    /*delete this maximum integer from list*/
        $= $  ||  big                            /*append   "     "       "    ───►  $. */
        end     /*while z*/                      /* [↑]  process all integers in a list.*/
    say 'largest concatenatated integer from '  left( space(@.j), w)    " is ─────► "    $
    end         /*j*/                            /* [↑]  process each list of integers. */
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
norm: arg i;  #= word(z, i);  er= '***error***';  if left(#, 1)=="-"  then #= substr(#, 2)
      if \datatype(#,'W')  then do; say er # "isn't an integer."; exit 13; end; return #/1


nums=[1,34,3,98,9,76,45,4]
see largestInt(8) + nl
nums=[54,546,548,60]
see largestInt(4) + nl

func largestInt len
l = ""
sorted = false
while not sorted
      sorted=true
      for i=1 to len-1
          a=string(nums[i])
          b=string(nums[i+1])
          if a+b<b+a
             temp = nums[i]
             nums[i] = nums[i+1]
             nums[i+1] = temp
             sorted=false ok
      next
end
for i=1 to len
    l+=string(nums[i])
next
return l


def icsort nums
  nums.sort { |x, y| "#{y}#{x}" <=> "#{x}#{y}" }
end

[[54, 546, 548, 60], [1, 34, 3, 98, 9, 76, 45, 4]].each do |c|
  p c # prints nicer in Ruby 1.8
  puts icsort(c).join
end


a1$ = "1, 34, 3, 98, 9, 76, 45, 4"
a2$ = "54,546,548,60"

print "Max Num ";a1$;" = ";maxNum$(a1$)
print "Max Num ";a2$;" = ";maxNum$(a2$)

function maxNum$(a1$)
while word$(a1$,i+1,",") <> ""
 i = i + 1
 a$(i) = trim$(word$(a1$,i,","))
wend

s = 1
while s = 1
 s = 0
 for j = 1 to i -1
  if a$(j)+a$(j+1) < a$(j+1)+a$(j) then
   h$      = a$(j)
   a$(j)   = a$(j+1)
   a$(j+1) = h$
   s       = 1
  end if
 next j
wend

for j = 1 to i
 maxNum$ = maxNum$ ; a$(j)
next j
end function


define catcmp(a, b)
{
   a = string(a);
   b = string(b);
   return strcmp(b+a, a+b);
}

define maxcat(arr)
{
   arr = arr[array_sort(arr, &catcmp)];
   variable result = "", elem;
   foreach elem (arr)
     result += string(elem);
   return result;
}

print("max of series 1 is " + maxcat([1, 34, 3, 98, 9, 76, 45, 4]));
print("max of series 2 is " + maxcat([54, 546, 548, 60]));


object LIFCI extends App {

  def lifci(list: List[Long]) = list.permutations.map(_.mkString).max

  println(lifci(List(1, 34, 3, 98, 9, 76, 45, 4)))
  println(lifci(List(54, 546, 548, 60)))
}


(define (cat . nums)  (apply string-append (map number->string nums)))

(define (my-compare a b)  (string>? (cat a b) (cat b a)))

(map  (lambda (xs) (string->number (apply cat (sort xs my-compare))))
      '((1 34 3 98 9 76 45 4) (54 546 548 60)))


#(
    (54  546  548  60)
    (1  34  3  98  9  76  45  4)
) do:[:ints |
    |resultString|

    "sort ints by padded strings (sort a copy - literals are immudatble),
     then collect their strings, then concatenate"
    resultString :=
        ((ints copy sort:[:a :b |
                |pad|
                pad := (a integerLog10) max:(b integerLog10).
                (a printString paddedTo:pad with:$0) > (b printString paddedTo:pad with:$0)])
            collect:#printString) asStringWith:''.
    Stdout printCR: resultString.
].


proc intcatsort {nums} {
    lsort -command {apply {{x y} {expr {"$y$x" - "$x$y"}}}} $nums
}


Function largestint(list)
	nums = Split(list,",")
	Do Until IsSorted = True
		IsSorted = True
		For i = 0 To UBound(nums)
			If i <> UBound(nums) Then
				a = nums(i)
				b = nums(i+1)
				If CLng(a&b) < CLng(b&a) Then
					tmpnum = nums(i)
					nums(i) = nums(i+1)
					nums(i+1) = tmpnum
					IsSorted = False
				End If
			End If
		Next
	Loop
	For j = 0 To UBound(nums)
		largestint = largestint & nums(j)
	Next
End Function

WScript.StdOut.Write largestint(WScript.Arguments(0))
WScript.StdOut.WriteLine


import "/sort" for Sort

var cmp = Fn.new { |x, y|
    var xy = Num.fromString(x.toString + y.toString)
    var yx = Num.fromString(y.toString + x.toString)
    return (xy - yx).sign
}

var findLargestSequence = Fn.new { |a|
    var b = Sort.merge(a, cmp)
    return b[-1..0].join()
}

var arrays = [
    [1, 34, 3, 98, 9, 76, 45, 4],
    [54, 546, 548, 60]
]
for (a in arrays) {
    System.print("%(a) -> %(findLargestSequence.call(a))")
}


fcn bigCI(ns){
   ns.apply("toString").sort(fcn(a,b){ (a+b)>(b+a) }).concat();
}


F lah(BigInt n, BigInt k)
   I k == 1
      R factorial(n)
   I k == n
      R BigInt(1)
   I k > n
      R BigInt(0)
   I k < 1 | n < 1
      R BigInt(0)
   R (factorial(n) * factorial(n - 1)) I/ (factorial(k) * factorial(k - 1)) I/ factorial(n - k)

print(‘Unsigned Lah numbers: L(n, k):’)
print(‘n/k ’, end' ‘ ’)
L(i) 13
   print(‘#11’.format(i), end' ‘ ’)
print()
L(row) 13
   print(‘#<4’.format(row), end' ‘ ’)
   L(i) 0 .. row
      V l = lah(row, i)
      print(‘#11’.format(l), end' ‘ ’)
   print()
print("\nMaximum value from the L(100, *) row:")
V maxVal = max((0.<100).map(a -> lah(100, a)))
print(maxVal)


BEGIN # calculate Lah numbers upto L( 12, 12 )                                      #
    PR precision 400 PR # set the precision for LONG LONG INT                       #
    # returns Lah Number L( n, k ), f must be a table of factorials to at least n   #
    PROC lah = ( INT n, k, []LONG LONG INT f )LONG LONG INT:
         IF   n = k          THEN 1
         ELIF n = 0 OR k = 0 THEN 0
         ELIF k = 1          THEN f[ n ]
         ELIF k > n          THEN 0
         ELSE
            # general case: ( n! * ( n - 1 )! ) / ( k! * ( k - 1 )! ) / ( n - k )!  #
            # we re-arrange the above to:                                           #
            #   (    n!      /    k! )      -- t1                                   #
            # * ( ( n - 1 )! / ( k - 1 )! ) -- t2                                   #
            # / ( n - k )!                                                          #
            LONG LONG INT t1 = f[ n     ] OVER f[ k     ];
            LONG LONG INT t2 = f[ n - 1 ] OVER f[ k - 1 ];
            ( t1 * t2 ) OVER f[ n - k ]
         FI # lah # ;
    INT max n       = 100; # max n for Lah Numbers                                  #
    INT max display =  12; # max n to display L( n, k ) values                      #
    # table of factorials up to max n                                               #
    [ 1 : max n ]LONG LONG INT factorial;
    BEGIN
        LONG LONG INT f := 1;
        FOR i TO UPB factorial DO factorial[ i ] := f *:= i OD
    END;
    # show the Lah numbers                                                          #
    print( ( "Unsigned Lah numbers", newline ) );
    print( ( "n/k  0" ) );
    FOR i FROM 1 TO max display DO print( ( whole( i, -11 ) ) ) OD;
    print( ( newline ) );
    FOR n FROM 0 TO max display DO
        print( ( whole( n, -2 ) ) );
        print( ( whole( lah( n, 0, factorial ), -4 ) ) );
        FOR k FROM 1 TO n DO
            print( ( whole( lah( n, k, factorial ), -11 ) ) )
        OD;
        print( ( newline ) )
    OD;
    # maximum value of a Lah number for n = 100                                     #
    LONG LONG INT max 100 := 0;
    FOR k FROM 0 TO 100 DO
        LONG LONG INT lah n k = lah( 100, k, factorial );
        IF lah n k > max 100 THEN max 100 := lah n k FI
    OD;
    print( ( "maximum Lah number for n = 100: ", whole( max 100, 0 ), newline ) )
END


begin % calculate Lah numbers upto L( 12, 12 )                                      %
    % sets lahNumber to L( n, k ), lahScale is returned as the power of 10          %
    % lahNumber should be multiplied by                                             %
    % f must be a table of factorials to at least n                                 %
    procedure L ( integer value n, k
                ; integer array f ( * )
                ; integer result lahNumber, lahScale
                ) ;
        if      n = k          then begin lahNumber := 1;      lahScale := 0 end
        else if n = 0 or k = 0 then begin lahNumber := 0;      lahScale := 0 end
        else if k = 1          then begin lahNumber := f( n ); lahScale := 0 end
        else if k > n          then begin lahNumber := 0;      lahScale := 0 end
        else begin
            % general case: ( n! * ( n - 1 )! ) / ( k! * ( k - 1 )! ) / ( n - k )!  %
            % Algol W has only 32 bit signed integers so we need to avoid overflow  %
            % we re-arrange the above to:                                           %
            %   ( n! / k! / ( n - k ) ! )  -- t1                                    %
            % * ( ( n - 1 )! / ( k - 1 )!  -- t2                                    %
            % and if necessary, reduce t1 and t2 by powers of 10                    %
            integer t1, t2, d1, d2, v;
            t1 := f( n     ) div f( k     ) div f( n - k );
            t2 := f( n - 1 ) div f( k - 1 );
            % calculate the number of digits for t1 and t2                          %
            lahScale := d1 := d2 := 0;
            v := t1; while v > 0 do begin d1 := d1 + 1; v := v div 10 end;
            v := t2; while v > 0 do begin d2 := d2 + 1; v := v div 10 end;
            if d1 + d2 > 8 then begin
                % the result will overflow reduce t1 and t2 by an appropriate power %
                % of 10 and set lahScale accordingly                                %
                while t1 rem 10 = 0 do begin lahScale := lahScale + 1; t1 := t1 div 10 end;
                while t2 rem 10 = 0 do begin lahScale := lahScale + 1; t2 := t2 div 10 end;
            end if_d1_plus_d2_gt_8;
            lahNumber := t1 * t2
        end L;
    % table of factorials up to 12                                 %
    integer array factorial ( 1 :: 12 );
    % compute the factorials                                       %
    begin
        integer f; f := 1;
        for i := 1 until 12 do begin f := f * i; factorial( i ) := f end
    end;
    % show the Lah numbers                                         %
    write( "Unsigned Lah numbers" );
    write( "n/k " );
    for i := 0 until 12 do writeon( i_w := 11, s_w := 0, i );
    for n := 0 until 12 do begin
        write( s_w := 2, i_w := 2, n );
        for k := 0 until n do begin
            integer lahNumber, lahScale;
            L( n, k, factorial, lahNumber, lahScale );
            writeon( S_W := 0, i_w := 11 - lahScale, lahNumber );
            for s := 1 until lahScale do writeon( s_w := 0, "0" )
        end for_k
    end for_n
end.


factorial: function [n]-> product 1..n

lah: function [n,k][
    if k=1 -> return factorial n
    if k=n -> return 1
    if k>n -> return 0
    if or? k<1 n<1 -> return 0
    return (((factorial n)*factorial n-1) / ((factorial k) * factorial k-1)) / factorial n-k
]

print @["n/k"] ++ map to [:string] 1..12 's -> pad s 10
print repeat "-" 136
loop 1..12 'x [
    print @[pad to :string x 3] ++ map to [:string] map 1..12 'y -> lah x y 's -> pad s 10
]


# syntax: GAWK -f LAH_NUMBERS.AWK
# converted from C
BEGIN {
    print("unsigned Lah numbers: L(n,k)")
    printf("n/k")
    for (i=0; i<13; i++) {
      printf("%11d",i)
    }
    printf("\n")
    for (row=0; row<13; row++) {
      printf("%-3d",row)
      for (i=0; i<row+1; i++) {
        printf(" %10d",lah(row,i))
      }
      printf("\n")
    }
    exit(0)
}
function factorial(n,  res) {
    res = 1
    if (n == 0) { return(res) }
    while (n > 0) { res *= n-- }
    return(res)
}
function lah(n,k) {
    if (k == 1) { return factorial(n) }
    if (k == n) { return(1) }
    if (k > n) { return(0) }
    if (k < 1 || n < 1) { return(0) }
    return (factorial(n) * factorial(n-1)) / (factorial(k) * factorial(k-1)) / factorial(n-k)
}


F ← (≥⟜0)◶⟨0,×´1+↕⟩
Lah ← {
  𝕨 𝕊 0: 0;
  0 𝕊 𝕩: 0;
  𝕨 𝕊 1: F 𝕨;
  n 𝕊 k:
  (n=k)⊑⟨((n ×○F n-1) ÷ k ×○F k-1) (0=⊢)◶÷‿0 F n-k, 1⟩
}

•Show Lah⌜˜↕12


#include <stdint.h>
#include <stdio.h>

uint64_t factorial(uint64_t n) {
    uint64_t res = 1;
    if (n == 0) return res;
    while (n > 0) res *= n--;
    return res;
}

uint64_t lah(uint64_t n, uint64_t k) {
    if (k == 1) return factorial(n);
    if (k == n) return 1;
    if (k > n) return 0;
    if (k < 1 || n < 1) return 0;
    return (factorial(n) * factorial(n - 1)) / (factorial(k) * factorial(k - 1)) / factorial(n - k);
}

int main() {
    int row, i;

    printf("Unsigned Lah numbers: L(n, k):\n");
    printf("n/k ");
    for (i = 0; i < 13; i++) {
        printf("%10d ", i);
    }
    printf("\n");
    for (row = 0; row < 13; row++) {
        printf("%-3d", row);
        for (i = 0; i < row + 1; i++) {
            uint64_t l = lah(row, i);
            printf("%11lld", l);
        }
        printf("\n");
    }

    return 0;
}


using System;
using System.Linq;
using System.Numerics;

namespace LahNumbers {
    class Program {
        static BigInteger Factorial(BigInteger n) {
            if (n == 0) return 1;
            BigInteger res = 1;
            while (n > 0) {
                res *= n--;
            }
            return res;
        }

        static BigInteger Lah(BigInteger n, BigInteger k) {
            if (k == 1) return Factorial(n);
            if (k == n) return 1;
            if (k > n) return 0;
            if (k < 1 || n < 1) return 0;
            return (Factorial(n) * Factorial(n - 1)) / (Factorial(k) * Factorial(k - 1)) / Factorial(n - k);
        }

        static void Main() {
            Console.WriteLine("Unsigned Lah numbers: L(n, k):");
            Console.Write("n/k ");
            foreach (var i in Enumerable.Range(0, 13)) {
                Console.Write("{0,10} ", i);
            }
            Console.WriteLine();
            foreach (var row in Enumerable.Range(0, 13)) {
                Console.Write("{0,-3}", row);
                foreach (var i in Enumerable.Range(0, row + 1)) {
                    var l = Lah(row, i);
                    Console.Write("{0,11}", l);
                }
                Console.WriteLine();
            }
            Console.WriteLine("\nMaximum value from the L(100, *) row:");
            var maxVal = Enumerable.Range(0, 100).Select(a => Lah(100, a)).Max();
            Console.WriteLine(maxVal);
        }
    }
}


// Reference: https://en.wikipedia.org/wiki/Lah_number#Identities_and_relations

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <map>
#include <gmpxx.h>

using integer = mpz_class;

class unsigned_lah_numbers {
public:
    integer get(int n, int k);
private:
    std::map<std::pair<int, int>, integer> cache_;
};

integer unsigned_lah_numbers::get(int n, int k) {
    if (k == n)
        return 1;
    if (k == 0 || k > n)
        return 0;
    auto p = std::make_pair(n, k);
    auto i = cache_.find(p);
    if (i != cache_.end())
        return i->second;
    integer result = (n - 1 + k) * get(n - 1, k) + get(n - 1, k - 1);
    cache_.emplace(p, result);
    return result;
}

void print_lah_numbers(unsigned_lah_numbers& uln, int n) {
    std::cout << "Unsigned Lah numbers up to L(12,12):\nn/k";
    for (int j = 1; j <= n; ++j)
        std::cout << std::setw(11) << j;
    std::cout << '\n';
    for (int i = 1; i <= n; ++i) {
        std::cout << std::setw(2) << i << ' ';
        for (int j = 1; j <= i; ++j)
            std::cout << std::setw(11) << uln.get(i, j);
        std::cout << '\n';
    }
}

int main() {
    unsigned_lah_numbers uln;
    print_lah_numbers(uln, 12);
    std::cout << "Maximum value of L(n,k) where n == 100:\n";
    integer max = 0;
    for (int k = 0; k <= 100; ++k)
        max = std::max(max, uln.get(100, k));
    std::cout << max << '\n';
    return 0;
}