In this HackerRank Lovely Triplets problem solution we have given P different lovely triplets and the minimum distance between each pair of nodes in the triplets Q and we need to draw a special graph.

HackerRank Lovely Triplets problem solution


Problem solution in Python.

#!/bin/python3

def choose(n, r):
    return n * (n-1) * (n-2) // (r * (r-1) * (r-2))
def product(xs):
    y = 1
    for x in xs:
        y *= x
    return y
def generate_primes(n):
    p = [True] * (n + 1)
    p[0] = False
    p[1] = False
    for i in range(n+1):
        if p[i]:
            yield i
            for j in range(2*i,n+1,i):
                p[j] = False
primes = list(generate_primes(5000))
def factorize(n):
    qs = []
    for p in primes:
        if p*p > n:
            break
        while n % p == 0:
            qs.append(p)
            n //= p
    if n != 1:
        qs.append(n)
    return qs
def core_size(q):
    return ((q - 1) // 2) * 3
def select_factors(p, q, width, memo):
    if p in memo:
        return memo[p]
    qs = [p, 1, 1]
    qv = core_size(q) + sum(qs)
    for i in range(min(width, p)):
        ps = [1, 1, 1]
        for r in factorize(p - i):
            ps[ps.index(min(ps))] *= r
        pv = core_size(q) + sum(ps)
        if i:
            nps, npv = select_factors(p - product(ps), q, width=width, memo=memo)
            pv += npv
        if pv < qv:
            qs = ps
            qv = pv
    memo[p] = (tuple(qs), qv)
    return memo[p]
def make_core(v, e, q):
    if q % 2 == 1:
        xs, v = [v, v+1, v+2], v+3
        for i in range(3):
            e.append((xs[i], xs[(i+1)%3]))
    else:
        xs, v = [v, v, v], v+1
    for i in range(3):
        for j in range(q//2 - 1):
            e.append((xs[i], v))
            xs[i] = v
            v += 1
    return xs, v
def make_triplets(v, e, q, ps):
    xs, v = make_core(v, e, q)
    for i in range(3):
        for _ in range(ps[i]):
            e.append((xs[i], v))
            v += 1
    return v
def make_coalesced_core(v, e, l):
    for i in range(l):
        e.append((v, v + i+1))
    v += l+1
    return v
p, q = map(int,input().split())
v = 0
e = []
if q == 2:
    while p:
        l = 3
        while choose(l+1,3) <= p:
            l += 1
        p -= choose(l,3)
        v = make_coalesced_core(v, e, l)
else:
    while p:
        ps, _ = select_factors(p, q, width=500, memo={})
        v = make_triplets(v, e, q, ps)
        p -= product(ps)
print(v, len(e))
assert v <= 100
for a, b in e:
    print(a+1, b+1)

{"mode":"full","isActive":false}


Problem solution in Java.

import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;

public class LovelyTriplets {
    public static void main(String[] args) throws Exception {
        Scanner in = new Scanner(System.in);
        int cases = 1;//in.nextInt();
        for (int testcase = 0; testcase < cases; testcase++) {
            int n = in.nextInt();
            int m = in.nextInt();
            lovelyTriplets(n, m);
        }
    }

    public static void lovelyTriplets(int n, int q) {
        if (q == 2) {
            lovelyTripletsTwo(n);
            return;
        }
        if (q == 3) {
            lovelyTripletsThree(n);
            return;
        }
        int best = Integer.MAX_VALUE;
        int bestIndex = -1;
        for (int i = 1; i < n; i++) {
            int[] b1 = bestThree(i);
            int[] b2 = bestThree(n-i);
            int sum = b1[0] +b1[1] + b1[2] + b2[0] + b2[1] + b2[2];
            if (sum < best) {
                best = sum;
                bestIndex = i;
            }
        }
        int[] b1 = bestThree(bestIndex);
        int[] b2 = bestThree(n-bestIndex);
        int sum = 0;
        for (int i : b1) sum+=i;
        for (int i : b2) sum+=i;
        int nodes = sum+3*(q-2);
        System.out.println(nodes + " " + nodes);
        int node = 7;
        for (int i = 0; i < b1[0]; i++) {
            System.out.println("1 " + node); node++;
        }
        for (int i = 0; i < b1[1]; i++) {
            System.out.println("2 " + node); node++;
        }
        for (int i = 0; i < b1[2]; i++) {
            System.out.println("3 " + node); node++;
        }
        for (int i = 0; i < b2[0]; i++) {
            System.out.println("4 " + node); node++;
        }
        for (int i = 0; i < b2[1]; i++) {
            System.out.println("5 " + node); node++;
        }
        for (int i = 0; i < b2[2]; i++) {
            System.out.println("6 " + node); node++;
        }
        System.out.println("1 4");
        System.out.println("2 5");
        System.out.println("3 6");
        int[] lasts = new int[]{4,5,6};
        for (int  i = 5; i <= q; i++) {
            for (int j = 0; j < 3; j++) {
                System.out.println(lasts[j] + " " + node);
                lasts[j] = node;
                node++;
            }
        }
        System.out.println(lasts[0] + " 2");
        System.out.println(lasts[1] + " 3");
        System.out.println(lasts[2] + " 1");

    }

    static void lovelyTripletsThree(int n) {
        int best = Integer.MAX_VALUE;
        int bestIndex = -1;
        for (int i = 1; i < n; i++) {
            int[] b1 = bestThree(i);
            int[] b2 = bestThree(n-i);
            int sum = b1[0] +b1[1] + b1[2] + b2[0] + b2[1] + b2[2];
            if (sum < best) {
                best = sum;
                bestIndex = i;
            }
        }
        int[] b1 = bestThree(bestIndex);
        int[] b2 = bestThree(n-bestIndex);
        int sum = 0;
        for (int i : b1) sum+=i;
        for (int i : b2) sum+=i;
        int nodes = sum+6;
        System.out.println(nodes + " " + nodes);
        int node = 7;
        for (int i = 0; i < b1[0]; i++) {
            System.out.println("1 " + node); node++;
        }
        for (int i = 0; i < b1[1]; i++) {
            System.out.println("2 " + node); node++;
        }
        for (int i = 0; i < b1[2]; i++) {
            System.out.println("3 " + node); node++;
        }
        for (int i = 0; i < b2[0]; i++) {
            System.out.println("4 " + node); node++;
        }
        for (int i = 0; i < b2[1]; i++) {
            System.out.println("5 " + node); node++;
        }
        for (int i = 0; i < b2[2]; i++) {
            System.out.println("6 " + node); node++;
        }
        System.out.println("1 2");
        System.out.println("2 3");
        System.out.println("3 1");
        System.out.println("4 5");
        System.out.println("5 6");
        System.out.println("6 4");

    }

    static int[] bestThree(int n) {
        int cube = (int)Math.pow(n, 1.0/3.0);
        for (int i = cube+1; i >= 1; i--) {
            if ((n%i) == 0) {
                int[] bt = bestTwo(n/i);
                return new int[]{i, bt[0], bt[1]};
            }
        }
        return new int[]{n, 1, 1};
    }

    static int[] bestTwo(int n) {
        int square = (int)Math.sqrt(n);
        for (int i = square+1; i >= 1; i--) {
            if ((n%i) == 0) {
                return new int[]{i, n/i};
            }
        }
        return new int[]{n, 1};
    }

    public static void lovelyTripletsTwo(int p) {
        int[] chooses = new int[34];
        for (int i = 3; i < 34; i++) {
            int val = i*(i-1)*(i-2)/6;
            chooses[i] = val;
        }



        int total = 0;
        List<Integer> flowers = new ArrayList<Integer>();
        while (total < p) {
            for (int i = 33; i >= 3; i--) {
                if (total + chooses[i] <= p) {
                    total += chooses[i];
                    flowers.add(i);
                    i++;
                }
            }
        }
        int numFlowers = flowers.size();
        int numLeaves = 0;
        for (int flower : flowers) numLeaves += flower;
        System.out.println((numFlowers + numLeaves) + " " + numLeaves);

        int nodeCount = 0;
        for (int flower : flowers) {
            int root = nodeCount+1;
            for (int i = 0; i < flower; i++) {
                System.out.println(root + " " + (root+i+1));
            }
            nodeCount = root + flower;
        }
    }

}

{"mode":"full","isActive":false}


Problem solution in C++.

#include <cassert>
#include <iostream>
#include <vector>
#include <limits>
#include <array>

using std::cin;
using std::cout;
using std::cerr;
using std::vector;


namespace {
  struct Edge {
    int node1, node2;
  };
}

using Edges = vector<Edge>;


static int maxNodeNumber(const Edges &edges)
{
  int result = -1;
  int n_edges = edges.size();

  for (int i=0; i!=n_edges; ++i) {
    result = std::max(result,edges[i].node1);
    result = std::max(result,edges[i].node2);
  }

  return result;
}


namespace {
  struct Graph {
    const Edges edges;
    const int n_nodes;

    Graph(const Edges &edges_arg,int n_arg)
    : edges(edges_arg),
      n_nodes(n_arg)
    {
    }

    Graph(const Edges &edges_arg)
    : Graph(edges_arg,maxNodeNumber(edges_arg)+1)
    {
    }
  };
}


static int factorial(int n)
{
  int result = 1;
  while (n>1) {
    result *= n;
    --n;
  }
  return result;
}


static int comb(int n,int k)
{
  if (k==3) {
    assert(n>=3);
    int result = 1;
    int stop = n-k;
    while (n>stop) {
      result *= n;
      --n;
    }
    return result/factorial(3);
  }

  return factorial(n)/(factorial(k)*factorial(n-k));
}


static int nStarGraphTriplets(int n_spokes)
{
  return comb(n_spokes,3);
}


static Edges starGraphEdges(int n_spokes)
{
  Edges edges;
  for (int i=0; i!=n_spokes; ++i) {
    edges.push_back(Edge{0,i+1});
  }
  return edges;
}


static void offsetEdges(Edges &edges,int n)
{
  int n_edges = edges.size();

  for (int i=0; i!=n_edges; ++i) {
    edges[i].node1 += n;
    edges[i].node2 += n;
  }
}


static void
  addOffsetEdgesTo(Edges &new_edges,int a_n_nodes,const Edges &b_edges)
{
  Edges additional_edges = b_edges;
  offsetEdges(additional_edges,a_n_nodes);
  new_edges.insert(
     new_edges.end(),additional_edges.begin(),additional_edges.end()
  );
}


typedef std::array<int,3> Triple;


namespace {
  struct BarbCombo : std::array<Triple,2> {
    BarbCombo(const Triple &arg0,const Triple &arg1)
    : std::array<Triple,2>{{arg0,arg1}}
    {
    }
  };
}


static BarbCombo makeBarbResults(const vector<int> &v)
{
  return {{v[0],v[1],v[2]},{v[3],v[4],v[5]}};
}


static int barb9NodeCount(const BarbCombo &barb_counts)
{
  int total = 0;
  int n_groups = barb_counts.size();

  int l = 4;

  for (int i=0; i!=n_groups; ++i) {
    if (barb_counts[i][0]!=0 && barb_counts[i][1]!=0 && barb_counts[i][2]!=0) {
      total += 3*l+barb_counts[i][0]+barb_counts[i][1]+barb_counts[i][2];
    }
  }

  return total;
}


static int barb9EdgeCount(const BarbCombo &barb_counts)
{
  return barb9NodeCount(barb_counts);
}


static bool hasLegalNodeCounts(const BarbCombo &barb_results)
{
  int n_nodes = barb9NodeCount(barb_results);
  int n_edges = barb9EdgeCount(barb_results);

  return (n_nodes<=100 && n_edges<=100);
}


static int barbTotal(const BarbCombo &results)
{
  int total = 0;
  for (int i=0, n_results=results.size(); i!=n_results; ++i) {
    total += results[i][0]*results[i][1]*results[i][2];
  }
  return total;
}


// Try to find a set of six numbers such that a*b*c + d*e*f == n
// Make sure that we can create a legal graph from whatever we return.
static BarbCombo findBarbCombo(int n)
{
  vector<int> v = {1,1,0,1,1,1};

  assert(n>=1);

  v[5] = n;

  for (;;) {
    for (;;) {
      BarbCombo results = makeBarbResults(v);

      if (!hasLegalNodeCounts(results)) {
        break;
      }

      int total = barbTotal(results);

      if (total==n) {
        return results;
      }

      if (total>n) {
        break;
      }

      ++v[5];
    }

    int i = 5;
    while (v[i]==1) {
      --i;
    }
    v[i] = 1;
    ++v[i-1];
  }
}


static Edges barbGraphEdges(int q,const Triple &barb_counts)
{
  if (barb_counts[0]*barb_counts[1]*barb_counts[2]==0) {
    return {};
  }

  assert(q>=3);

  Edges edges;
  int base = 0;

  if (q%2==0) {
    edges = {{0,1},{0,2},{0,3}};
    base = 1;
  }
  else {
    edges = {{0,1},{0,2},{1,2}};
    base = 0;
  }

  int iter = 0;

  while (q>=5+iter*2) {
    for (int i=0; i!=3; ++i) {
      edges.push_back(Edge{base+iter*3+i,base+iter*3+i+3});
    }
    ++iter;
  }

  int offset = base+iter*3;
  int v = offset+3;

  for (int i=0; i!=3; ++i) {
    for (int j=0; j!=barb_counts[i]; ++j) {
      edges.push_back(Edge{i+offset,v});
      ++v;
    }
  }

  return edges;
}



static Graph operator+(const Graph &a,const Graph &b)
{
  Edges new_edges = a.edges;
  addOffsetEdgesTo(new_edges,a.n_nodes,b.edges);
  return Graph(new_edges);
}


static Edges makeMultiStarGraphEdges(int p)
{
  Edges edges;
  int n_nodes = 0;

  while (p>0) {
    int n_spokes = 3;
    while (nStarGraphTriplets(n_spokes+1)<=p) {
      ++n_spokes;
    }
    addOffsetEdgesTo(edges,n_nodes,starGraphEdges(n_spokes));
    n_nodes = maxNodeNumber(edges)+1;
    p -= nStarGraphTriplets(n_spokes);
  }

  return edges;
}


static Graph createSpecialGraph(int p,int q)
{
  if (q==2) {
    return Graph(makeMultiStarGraphEdges(p));
  }

  BarbCombo barb_combo = findBarbCombo(p);
  Edges edges0 = barbGraphEdges(q,barb_combo[0]);
  Edges edges1 = barbGraphEdges(q,barb_combo[1]);

  return Graph(edges0) + Graph(edges1);
}


int main()
{
  int p,q; cin >> p >> q;
  Graph g = createSpecialGraph(p,q);
  int m = g.edges.size();
  int n = g.n_nodes;
  cout << n << " " << m << "\n";
  for (int i=0; i!=m; ++i) {
    cout << g.edges[i].node1+1 << " " << g.edges[i].node2+1 << "\n";
  }
}

{"mode":"full","isActive":false}


Problem solution in C.

#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* readline();
char** split_string(char*);

int** makeGraph(int p, int q, int startv, int *result_count){
    if(p == 0){
        *result_count = 1;
        int** toreturn = malloc(sizeof(int*));
        toreturn[0] = malloc(2*sizeof(int));
        toreturn[0][0] = 0;
        toreturn[0][1] = 0;
        return toreturn;
    }
    if(q == 2){
        int numspokes = 3;
        while(numspokes*(numspokes - 1)*(numspokes - 2) <= 6*p){
            numspokes++;
        }
        numspokes--;

        int tempresult_count;
        int** graph = makeGraph(p - (numspokes*(numspokes - 1)*(numspokes - 2))/6, q, startv + 1 + numspokes, &tempresult_count);
        *result_count = tempresult_count + numspokes;
        graph = realloc(graph, (*result_count)*sizeof(int*));
        for(int i = 0; i < numspokes; i++){
            graph[tempresult_count + i] = malloc(2*sizeof(int));
            graph[tempresult_count + i][0] = startv + 1;
            graph[tempresult_count + i][1] = startv + i + 2;
        }
        graph[0][0] += numspokes + 1;
        graph[0][1] += numspokes;
        return graph;
    }
    else{
        int factor1[q - 2];
        int factor2[q - 2];
        int factor3[q - 2];
        int currp = p;
        int extranum = 3*(q - 2);
        for(int i = 0; i < q - 2; i++){
            if(currp == 0){
                factor1[i] = 0;
                factor2[i] = 0;
                factor3[i] = 0;
            }
            else{
                factor1[i] = 1;
                while(factor1[i]*factor1[i]*factor1[i] <= currp){
                    factor1[i]++;
                }
                factor1[i]--;
                factor2[i] = factor1[i];
                while(factor1[i]*factor2[i]*factor2[i] <= currp){
                    factor2[i]++;
                }
                factor2[i]--;
                factor3[i] = factor2[i];
                while(factor1[i]*factor2[i]*factor3[i] <= currp){
                    factor3[i]++;
                }
                factor3[i]--;
                currp -= factor1[i]*factor2[i]*factor3[i];
                extranum += factor1[i] + factor2[i] + factor3[i];
            }
        }

        int tempresult_count;
        int** graph = makeGraph(currp, q, startv + extranum, &tempresult_count);
        *result_count = tempresult_count + extranum;
        graph = realloc(graph, (*result_count)*sizeof(int*));
        graph[tempresult_count] = malloc(2*sizeof(int));
        graph[tempresult_count][0] = startv + 1;
        graph[tempresult_count][1] = startv + 3*(q - 2);
        for(int i = 0; i < 3*(q - 2) - 1; i++){
            graph[tempresult_count + i + 1] = malloc(2*sizeof(int));
            graph[tempresult_count + i + 1][0] = startv + i + 1;
            graph[tempresult_count + i + 1][1] = startv + i + 2;
        }
        int index = tempresult_count + 3*(q - 2);
        int numvertex = 3*(q - 2);
        for(int i = 0; i < q - 2; i++){
            for(int j = 0; j < factor1[i]; j++){
                graph[index] = malloc(2*sizeof(int));
                graph[index][0] = startv + i + 1;
                graph[index][1] = startv + numvertex + 1;
                index++;
                numvertex++;
            }
            for(int j = 0; j < factor2[i]; j++){
                graph[index] = malloc(2*sizeof(int));
                graph[index][0] = startv + (q - 2) + i + 1;
                graph[index][1] = startv + numvertex + 1;
                index++;
                numvertex++;
            }
            for(int j = 0; j < factor3[i]; j++){
                graph[index] = malloc(2*sizeof(int));
                graph[index][0] = startv + 2*(q - 2) + i + 1;
                graph[index][1] = startv + numvertex + 1;
                index++;
                numvertex++;
            }
        }

        graph[0][0] += extranum;
        graph[0][1] += extranum;
        return graph;
    }    
}

int main()
{
    char** PQ = split_string(readline());

    char* P_endptr;
    char* P_str = PQ[0];
    int P = strtol(P_str, &P_endptr, 10);

    if (P_endptr == P_str || *P_endptr != '\0') { exit(EXIT_FAILURE); }

    char* Q_endptr;
    char* Q_str = PQ[1];
    int Q = strtol(Q_str, &Q_endptr, 10);

    if (Q_endptr == Q_str || *Q_endptr != '\0') { exit(EXIT_FAILURE); }

    int result_count;
    int** result = makeGraph(P, Q, 0, &result_count);
    for(int i = 0; i < result_count; i++){
        printf("%d %d\n", result[i][0], result[i][1]);
    }
}

char* readline() {
    size_t alloc_length = 1024;
    size_t data_length = 0;
    char* data = malloc(alloc_length);

    while (true) {
        char* cursor = data + data_length;
        char* line = fgets(cursor, alloc_length - data_length, stdin);

        if (!line) { break; }

        data_length += strlen(cursor);

        if (data_length < alloc_length - 1 || data[data_length - 1] == '\n') { break; }

        size_t new_length = alloc_length << 1;
        data = realloc(data, new_length);

        if (!data) { break; }

        alloc_length = new_length;
    }

    if (data[data_length - 1] == '\n') {
        data[data_length - 1] = '\0';
    }

    data = realloc(data, data_length);

    return data;
}

char** split_string(char* str) {
    char** splits = NULL;
    char* token = strtok(str, " ");

    int spaces = 0;

    while (token) {
        splits = realloc(splits, sizeof(char*) * ++spaces);
        if (!splits) {
            return splits;
        }

        splits[spaces - 1] = token;

        token = strtok(NULL, " ");
    }

    return splits;
}

{"mode":"full","isActive":false}