A triangulation of a convex polygon is formed by drawing diagonals between non-adjacent vertices (corners) such that the diagonals never intersect. The problem is to find the cost of triangulation with the minimum cost. The cost of a triangulation is sum of the weights of its component triangles. Weight of each triangle is its perimeter (sum of lengths of all sides)
See following example taken from this source.

Two triangulations of the same convex pentagon. The triangulation on the left has a cost of 8 + 2?2 + 2?5 (approximately 15.30), the one on the right has a cost of 4 + 2?2 + 4?5 (approximately 15.77).
This problem has recursive substructure. The idea is to divide the polygon into three parts: a single triangle, the sub-polygon to the left, and the sub-polygon to the right. We try all possible divisions like this and find the one that minimizes the cost of the triangle plus the cost of the triangulation of the two sub-polygons.
Let Minimum Cost of triangulation of vertices from i to j be minCost(i, j)
If j < i + 2 Then
minCost(i, j) = 0
Else
minCost(i, j) = Min { minCost(i, k) + minCost(k, j) + cost(i, k, j) }
Here k varies from 'i+1' to 'j-1'
Cost of a triangle formed by edges (i, j), (j, k) and (k, i) is
cost(i, j, k) = dist(i, j) + dist(j, k) + dist(k, i)
Following is implementation of above naive recursive formula.
C++
#include <iostream>
#include <cmath>
#define MAX 1000000.0
using namespace std;
struct Point
{
int x, y;
};
double min( double x, double y)
{
return (x <= y)? x : y;
}
double dist(Point p1, Point p2)
{
return sqrt ((p1.x - p2.x)*(p1.x - p2.x) +
(p1.y - p2.y)*(p1.y - p2.y));
}
double cost(Point points[], int i, int j, int k)
{
Point p1 = points[i], p2 = points[j], p3 = points[k];
return dist(p1, p2) + dist(p2, p3) + dist(p3, p1);
}
double mTC(Point points[], int i, int j)
{
if (j < i+2)
return 0;
double res = MAX;
for ( int k=i+1; k<j; k++)
res = min(res, (mTC(points, i, k) + mTC(points, k, j) +
cost(points, i, k, j)));
return res;
}
int main()
{
Point points[] = {{0, 0}, {1, 0}, {2, 1}, {1, 2}, {0, 2}};
int n = sizeof (points)/ sizeof (points[0]);
cout << mTC(points, 0, n-1);
return 0;
}
|
Java
class Point
{
int x, y;
public Point( int x, int y)
{
this .x = x;
this .y = y;
}
public double dist(Point p)
{
return Math.sqrt(( this .x - p.x) * ( this .x - p.x)
+ ( this .y - p.y) * ( this .y - p.y));
}
}
class GFG
{
public static double MWT(Point[] vertices, int i, int j)
{
if (j < i + 2 )
{
return 0 ;
}
double cost = Double.MAX_VALUE;
for ( int k = i + 1 ; k <= j - 1 ; k++)
{
double weight = vertices[i].dist(vertices[j])
+ vertices[j].dist(vertices[k])
+ vertices[k].dist(vertices[i]);
cost = Double.min(cost,
weight + MWT(vertices, i, k)
+ MWT(vertices, k, j));
}
return cost;
}
public static void main(String[] args)
{
Point[] vertices
= { new Point( 0 , 0 ), new Point( 2 , 0 ),
new Point( 2 , 1 ), new Point( 1 , 2 ),
new Point( 0 , 1 ) };
System.out.println(MWT(vertices,
0 , vertices.length - 1 ));
}
}
|
Python3
from math import sqrt
MAX = 1000000.0
def dist(p1, p2):
return sqrt((p1[ 0 ] - p2[ 0 ]) * (p1[ 0 ] - p2[ 0 ]) + \
(p1[ 1 ] - p2[ 1 ]) * (p1[ 1 ] - p2[ 1 ]))
def cost(points, i, j, k):
p1 = points[i]
p2 = points[j]
p3 = points[k]
return dist(p1, p2) + dist(p2, p3) + dist(p3, p1)
def mTC(points, i, j):
if (j < i + 2 ):
return 0
res = MAX
for k in range (i + 1 , j):
res = min (res, (mTC(points, i, k) + \
mTC(points, k, j) + \
cost(points, i, k, j)))
return round (res, 4 )
points = [[ 0 , 0 ], [ 1 , 0 ], [ 2 , 1 ], [ 1 , 2 ], [ 0 , 2 ]]
n = len (points)
print (mTC(points, 0 , n - 1 ))
|
C#
using System;
using System.Collections.Generic;
public class Point {
public int x, y;
public Point( int x, int y) {
this .x = x;
this .y = y;
}
public double dist(Point p) {
return Math.Sqrt(( this .x - p.x) * ( this .x - p.x) +
( this .y - p.y) * ( this .y - p.y));
}
}
public class GFG {
public static double MWT(Point[] vertices, int i, int j) {
if (j < i + 2) {
return 0;
}
double cost = 9999999999999.09;
for ( int k = i + 1; k <= j - 1; k++) {
double weight = vertices[i].dist(vertices[j]) +
vertices[j].dist(vertices[k])
+ vertices[k].dist(vertices[i]);
cost = Math.Min(cost, weight +
MWT(vertices, i, k) +
MWT(vertices, k, j));
}
return Math.Round(cost,4);
}
public static void Main(String[] args) {
Point[] vertices = { new Point(0, 0),
new Point(2, 0),
new Point(2, 1),
new Point(1, 2),
new Point(0, 1) };
Console.WriteLine(MWT(vertices, 0, vertices.Length - 1));
}
}
|
Javascript
const MAX = 1.79769e+308;
function min(x, y)
{
return (x <= y)? x : y;
}
function dist(p1, p2)
{
return Math.sqrt((p1[0] - p2[0])*(p1[0] - p2[0]) + (p1[1] - p2[1])*(p1[1] - p2[1]));
}
function cost(points, i, j, k)
{
p1 = points[i], p2 = points[j], p3 = points[k];
return dist(p1, p2) + dist(p2, p3) + dist(p3, p1);
}
function mTC(points, i, j)
{
if (j < i+2){
return 0;
}
let res = MAX;
for (let k=i+1; k<j; k++){
res = min(res, (mTC(points, i, k) + mTC(points, k, j) + cost(points, i, k, j)));
}
return res;
}
{
let points = [[0, 0], [1, 0], [2, 1], [1, 2],[0, 2]]
let n = points.length;
console.log(mTC(points, 0, n-1));
}
|
Output:
15.3006
Time Complexity: O(2n)
Space Complexity: O(n) for the recursive stack space.
The above problem is similar to Matrix Chain Multiplication. The following is recursion tree for mTC(points[], 0, 4).

It can be easily seen in the above recursion tree that the problem has many overlapping subproblems. Since the problem has both properties: Optimal Substructure and Overlapping Subproblems, it can be efficiently solved using dynamic programming.
Following is C++ implementation of dynamic programming solution.
C++
#include <iostream>
#include <cmath>
#define MAX 1000000.0
using namespace std;
struct Point
{
int x, y;
};
double min( double x, double y)
{
return (x <= y)? x : y;
}
double dist(Point p1, Point p2)
{
return sqrt ((p1.x - p2.x)*(p1.x - p2.x) +
(p1.y - p2.y)*(p1.y - p2.y));
}
double cost(Point points[], int i, int j, int k)
{
Point p1 = points[i], p2 = points[j], p3 = points[k];
return dist(p1, p2) + dist(p2, p3) + dist(p3, p1);
}
double mTCDP(Point points[], int n)
{
if (n < 3)
return 0;
double table[n][n];
for ( int gap = 0; gap < n; gap++)
{
for ( int i = 0, j = gap; j < n; i++, j++)
{
if (j < i+2)
table[i][j] = 0.0;
else
{
table[i][j] = MAX;
for ( int k = i+1; k < j; k++)
{
double val = table[i][k] + table[k][j] + cost(points,i,j,k);
if (table[i][j] > val)
table[i][j] = val;
}
}
}
}
return table[0][n-1];
}
int main()
{
Point points[] = {{0, 0}, {1, 0}, {2, 1}, {1, 2}, {0, 2}};
int n = sizeof (points)/ sizeof (points[0]);
cout << mTCDP(points, n);
return 0;
}
|
Java
import java.util.*;
class GFG
{
static class Point {
int x, y;
Point( int x, int y)
{
this .x = x;
this .y = y;
}
}
static double min( double x, double y)
{
return (x <= y) ? x : y;
}
static double dist(Point p1, Point p2)
{
return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x)
+ (p1.y - p2.y) * (p1.y - p2.y));
}
static double cost(Point points[], int i, int j, int k)
{
Point p1 = points[i], p2 = points[j],
p3 = points[k];
return dist(p1, p2) + dist(p2, p3) + dist(p3, p1);
}
static double mTCDP(Point points[], int n)
{
if (n < 3 )
return 0 ;
double [][] table = new double [n][n];
for ( int gap = 0 ; gap < n; gap++) {
for ( int i = 0 , j = gap; j < n; i++, j++) {
if (j < i + 2 )
table[i][j] = 0.0 ;
else {
table[i][j] = 1000000.0 ;
for ( int k = i + 1 ; k < j; k++) {
double val
= table[i][k] + table[k][j]
+ cost(points, i, j, k);
if (table[i][j] > val)
table[i][j] = val;
}
}
}
}
return table[ 0 ][n - 1 ];
}
public static void main(String[] args)
{
Point[] points = { new Point( 0 , 0 ), new Point( 1 , 0 ),
new Point( 2 , 1 ), new Point( 1 , 2 ),
new Point( 0 , 2 ) };
int n = points.length;
System.out.println(mTCDP(points, n));
}
}
|
Python3
import math
class GFG:
class Point:
x = 0
y = 0
def __init__( self , x, y):
self .x = x
self .y = y
@staticmethod
def min (x, y):
return x if (x < = y) else y
@staticmethod
def dist(p1, p2):
return math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))
@staticmethod
def cost(points, i, j, k):
p1 = points[i]
p2 = points[j]
p3 = points[k]
return GFG.dist(p1, p2) + GFG.dist(p2, p3) + GFG.dist(p3, p1)
@staticmethod
def mTCDP(points, n):
if (n < 3 ):
return 0
table = [[ 0.0 ] * (n) for _ in range (n)]
gap = 0
while (gap < n):
i = 0
j = gap
while (j < n):
if (j < i + 2 ):
table[i][j] = 0.0
else :
table[i][j] = 1000000.0
k = i + 1
while (k < j):
val = table[i][k] + table[k][j] + \
GFG.cost(points, i, j, k)
if (table[i][j] > val):
table[i][j] = val
k + = 1
i + = 1
j + = 1
gap + = 1
return table[ 0 ][n - 1 ]
if __name__ = = "__main__" :
points = [GFG.Point( 0 , 0 ), GFG.Point( 1 , 0 ), GFG.Point(
2 , 1 ), GFG.Point( 1 , 2 ), GFG.Point( 0 , 2 )]
n = len (points)
print (GFG.mTCDP(points, n))
|
C#
using System;
public class Point {
public int x;
public int y;
}
public static class Globals {
public const double MAX = 1000000.0;
public static double min( double x, double y)
{
return (x <= y) ? x : y;
}
public static double dist(Point p1, Point p2)
{
return Math.Sqrt((p1.x - p2.x) * (p1.x - p2.x)
+ (p1.y - p2.y) * (p1.y - p2.y));
}
public static double cost(Point[] points, int i, int j,
int k)
{
Point p1 = points[i];
Point p2 = points[j];
Point p3 = points[k];
return (dist(p1, p2) + dist(p2, p3) + dist(p3, p1));
}
public static double mTCDP(Point[] points, int n)
{
if (n < 3) {
return 0;
}
double [, ] table = new double [n, n];
;
for ( int gap = 0; gap < n; gap++) {
for ( int i = 0, j = gap; j < n; i++, j++) {
if (j < i + 2) {
table[i, j] = 0.0;
}
else {
table[i, j] = MAX;
for ( int k = i + 1; k < j; k++) {
double val
= table[i, k] + table[k, j]
+ cost(points, i, j, k);
if (table[i, j] > val) {
table[i, j] = val;
}
}
}
}
}
return table[0, n - 1];
}
public static void Main()
{
Point[] points = { new Point(){ x = 0, y = 0 },
new Point(){ x = 1, y = 0 },
new Point(){ x = 2, y = 1 },
new Point(){ x = 1, y = 2 },
new Point(){ x = 0, y = 2 } };
int n = points.Length;
Console.Write(mTCDP(points, n));
}
}
|
Javascript
const MAX = 1000000.0;
class Point {
constructor(x, y) {
this .x = x;
this .y = y;
}
}
function min(x, y) {
return x <= y ? x : y;
}
function dist(p1, p2) {
return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
function cost(points, i, j, k) {
let p1 = points[i],
p2 = points[j],
p3 = points[k];
return dist(p1, p2) + dist(p2, p3) + dist(p3, p1);
}
function mTCDP(points, n) {
if (n < 3) return 0;
let table = new Array(n);
for (let i = 0; i < n; i++) {
table[i] = new Array(n);
}
for (let gap = 0; gap < n; gap++) {
for (let i = 0, j = gap; j < n; i++, j++) {
if (j < i + 2) {
table[i][j] = 0;
} else {
table[i][j] = MAX;
for (let k = i + 1; k < j; k++) {
let val = table[i][k] + table[k][j] + cost(points, i, j, k);
if (table[i][j] > val) {
table[i][j] = val;
}
}
}
}
}
return table[0][n - 1];
}
let points = [ new Point(0, 0), new Point(1, 0), new Point(2, 1), new Point(1, 2), new Point(0, 2)];
let n = points.length;
let result = mTCDP(points, n);
console.log(Math.ceil(result * 10000) / 10000);
|
Output:
15.3006
Time complexity of the above dynamic programming solution is O(n3).
Auxiliary Space: O(n*n)
Please note that the above implementations assume that the points of convex polygon are given in order (either clockwise or anticlockwise)
Exercise:
Extend the above solution to print triangulation also. For the above example, the optimal triangulation is 0 3 4, 0 1 3, and 1 2 3.
Sources:
http://www.cs.utexas.edu/users/djimenez/utsa/cs3343/lecture12.html
http://www.cs.utoronto.ca/~heap/Courses/270F02/A4/chains/node2.html
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!