Algorithm: Circuit Routing Problem (Dynamic Programming)

📢 This article was translated by gemini-3-flash-preview

Problem Description

A circuit board has $n$ terminals on both the top and bottom sides. According to the circuit design, $(i, \pi(i))$ represents a connection between the top terminal $i$ and the bottom terminal $\pi(i)$, referred to as the $i$-th net.

The $\pi(i)$ permutation shown below is $\{8, 7, 4, 2, 5, 1, 9, 3, 10, 6\}$. For any $1 \le i < j \le n$, net $i$ and net $j$ intersect if and only if $\pi(i) > \pi(j)$.

Circuit Routing Diagram

When manufacturing the circuit board, these $n$ nets must be distributed across multiple insulating layers. Nets on the same layer must not intersect. We need to determine which nets to place on a single layer to maximize the total number of connections. This means finding the Maximum Non-crossing Subset (MNS) of the set $Nets=\{ (i,\pi(i)), 1 \le i \le n \}$.

Problem Analysis

Let $N(i,j)=\{ t \mid (t,\pi(t)) \in Nets, t \le i, \pi(t) \le j \}$. The maximum non-crossing subset of $N(i,j)$ is $MNS(i,j)$, and its size is $size(i,j) = |MNS(i,j)|$.

Analysis shows that this problem exhibits optimal substructure. For a circuit routing problem of size $n$, we can construct the following recurrence:

$$ \begin{align*} &(1) \ \text{When } i=1, \\ &size(1,j)= \begin{cases} 0, & \text{j < } \pi(1) \\ 1, & \text{otherwise} \end{cases} \\ &(2) \ \text{When } i>1, \\ &size(i,j)= \begin{cases} size(i-1,j), & \text{j < } \pi(i) \\ \max\{size(i-1,j), size(i-1,\pi(i)-1)+1\}, & \text{otherwise} \end{cases} \end{align*} $$

C Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <stdio.h>
#include <stdlib.h>

#define N 10    // Problem size

// Calculate the maximum number of non-crossing connections
void maxNum(int pi[], int **size);

// Construct the maximum non-crossing subset; net[i] stores the top terminal index
int constructSet(int pi[], int **size, int *net);

int main(void){
    // Index starts from 1
    int pi[N+1] = {0, 8, 7, 4, 2, 5, 1, 9, 3, 10, 6};
    int net[N];

    int **size;
    size = (int**)malloc(sizeof(int*)*(N+1));
    for(int i=0; i<N+1; i++)
        size[i]=(int*)malloc(sizeof(int)*(N+1));
    
    maxNum(pi, size);
    int m = constructSet(pi, size, net);   
    
    printf("Maximum non-crossing connections: %d\n", m);
    printf("Nets included:\n");
    for(int i=0; i<m; i++){
        printf("(%d,%d)\n", net[i], pi[net[i]]);
    }

    return 0;
}

void maxNum(int pi[], int **size){
    // size[i][j]: max non-crossing connections for board with i top and j bottom terminals
    int i, j;

    // case when i=1
    for(j=0; j<pi[1]; j++)
        size[1][j] = 0;

    for(j=pi[1]; j<=N; j++)
        size[1][j] = 1;

    for(i=2; i<N; i++){
        // when j < pi(i)
        for(j=0; j<pi[i]; j++)
            size[i][j] = size[i-1][j];   

        // when j >= pi(i)
        for(j=pi[i]; j<=N; j++)
            size[i][j] = size[i-1][j] >= size[i-1][pi[i]-1]+1 ? size[i-1][j] : size[i-1][pi[i]-1]+1;
    }

    // Maximum connections at size[N][N]
    size[N][N] = size[N-1][N] >= size[N-1][pi[N]-1]+1 ? size[N-1][N] : size[N-1][pi[N]-1]+1;
}

// Construct the MNS set, net[i] stores the top terminal index
int constructSet(int pi[], int **size, int *net){
    int i;
    int j = N;
    int m = 0;    // Counter for connections in the MNS

    for(i=N; i>1; i--){ 
        // If the size changed, (i, pi[i]) is part of the subset
        if(size[i][j] != size[i-1][j]){
            net[m++] = i; // Record i, increment count
            j = pi[i] - 1;  // Update the bottom terminal range limit
        }
    }

    // handle when i=1
    if(j >= pi[1])
        net[m++] = 1;

    return m;
}

Others

While searching, I came across an existing article: Algorithm Design and Analysis — Circuit Routing (Dynamic Programming)

References

LaTeX Formula Handbook

Using LaTeX in Typora: Left-aligning multi-line formulas

Three methods to dynamically allocate a 2D array using malloc