project euler -- problem 68

Consider the following "magic" 3-gon ring, filled with the numbers 1 to 6, and each line adding to nine.

Working clockwise, and starting from the group of three with the numerically lowest external node (4,3,2 in this example), each solution can be described uniquely. For example, the above solution can be described by the set: 4,3,2; 6,2,1; 5,1,3.

It is possible to complete the ring with four different totals: 9, 10, 11, and 12. There are eight solutions in total.

Total      Solution Set
9        4,2,3; 5,3,1; 6,1,2
9        4,3,2; 6,2,1; 5,1,3
10      2,3,5; 4,5,1; 6,1,3
10      2,5,3; 6,3,1; 4,1,5
11      1,4,6; 3,6,2; 5,2,4
11      1,6,4; 5,4,2; 3,2,6
12      1,5,6; 2,6,4; 3,4,5
12      1,6,5; 3,5,4; 2,4,6
By concatenating each group it is possible to form 9-digit strings; the maximum string for a 3-gon ring is 432621513.

Using the numbers 1 to 10, and depending on arrangements, it is possible to form 16- and 17-digit strings. What is the maximum 16-digit string for a "magic" 5-gon ring?


----
This is a very interesting problem, it tooks me several hours to solve it. There are many details need to consider.

Firstly, the nodes are divided into inNode and outNode. I defined getNode to generate all the combination of inNode and outNode.

The inNode set (iv) was used to generate all the possible combination of innode groups. All the possible sums of the innode group and outnode were further calculated. Only those have a same sum were retained.

If these innode groups have more than one combination, iterate all the possible combinations. Each combination (innode.sel) should passed the criteria of each innode was used two times, and sorted by inNodeSort, which make sure that one time the innode was used in the middle, the other time it should be used in the end, or vice versa.

The innode group and outnode were then combined to form a matrix, this matrix was sorted to let the gon-ring starting from the lowest outnode, and the path is smallest. If the rowSums of this matrix is unique, it means one of the possible gon-ring solution was found. Then concatenating each number to form a digit string.

?View Code RSPLUS
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
getNode <- function(num, n) {
    inNode <- t(combn(num, n))
    outNode <- sapply(1:nrow(inNode), function(i) num[!num %in% inNode[i,]])
    outNode <- t(outNode)
    s <- rowSums(inNode) * 2 + rowSums(outNode)
    idx <- s %% n == 0
    inNode <- inNode[idx,]
    outNode <- outNode[idx,]
    res <- list(inNode=inNode, outNode=outNode)
    return(res)
}
 
getGonRingDigit <- function(iv, ov){
    innode <- t(combn(iv,2))
    n <- length(ov)
 
    cs <- outer(rowSums(innode), ov, "+")
    cnt <- table(cs)
    cnt <- cnt[cnt >= n]
    s <- as.numeric(names(cnt))
 
    result <- c()
    for (x in s) {
        ss <- apply(cs, 2, function(i) which(i==x))
        len <- sapply(ss, length)
        if (any(len == 0)) {
            next
        }
 
        idx <- t(combn(unlist(ss), n))
        ii <- apply(idx, 1, function(i) {
            all(colSums(sapply(ss, function(j) i %in% j)) == 1)
        })
        idx <- idx[ii,]
        nr <- nrow(idx)
        if (is.null(nr)) {
            idx <- matrix(idx, nrow=1)
            nr <- nrow(idx)
        }
        if ( length(nr) == 0) {
            next
        }
 
        for(i in 1:nr) {
            innode.sel <- innode[idx[i,],]
            if (any(table(innode.sel) != 2)) {
                next
            }
            innode.sel <- inNodeSort(innode.sel)
            outnode <- sort(ov, decreasing=T)
            result <- c(result, gonRingNumber(innode.sel, outnode))
        }
    }
    if (is.null(result)) {
        result <- NA
    }
    return(result)
}
 
inNodeSort <- function(innode) {
    innode <- innode[order(rowSums(innode)),]
    iicache <- c()
    for (j in 1:ncol(innode)) {
        repeat {
            count <- table(innode[,j])
            dup <- names(count[count > 1])
            if(is.null(dup) || is.na(dup) || length(dup) == 0) {
                break
            }
            iis <- which(innode[,j] == dup[1])
            if (iis[2] %in% iicache) {
                ii <- iis[1]
                iicache <- c(iicache, ii)
            } else {
                ii <- iis[2]
                iicache <- c(iicache,ii)
            }
            innode[ii,] <- rev(innode[ii,])
        }
    }
    return(innode)
}
 
setGonOrder <- function(d) {
    dd <- d[order(d[,1]),]
    for (i in 2:(nrow(dd)-1)) {
        j <- which(dd[, ncol(dd)-1]  == dd[(i-1), ncol(dd)])
        if (length(j) != 0 && !is.na(j)) {
            tmp <- dd[i,]
            dd[i,] <- dd[j,]
            dd[j,] <- tmp
        }
    }
    return(dd)
}
 
gonRingNumber <- function(innode, outnode) {
    res <- character(2)
    d <- cbind(outnode, innode)
    if (length(unique(rowSums(d))) == 1 ) {
        res[1] <- gonRingNumber_internal(d)
    } else {
        res[1] <- NA
    }
    d <- cbind(innode, outnode)
    d <- d[,rev(1:ncol(d))]
    if (length(unique(rowSums(d))) == 1 ) {
        res[2] <- gonRingNumber_internal(d)
    } else {
        res[2] <- NA
    }
    return(res)
}
 
gonRingNumber_internal <- function(d) {
    d <- setGonOrder(d)
    n <- as.numeric(t(d))
    res <- paste(n, collapse="")
    return(res)
}
 
num <- 1:10
n <- 5
node <- getNode(num,n)
inNode <- node$inNode
outNode <- node$outNode
idx <- apply(inNode, 1, function(i) ! 10 %in% i)
inNode <- inNode[idx,]
outNode <- outNode[idx,]
res <- lapply(1:nrow(inNode), function(i)
             getGonRingDigit(inNode[i,], outNode[i,]))
cat("Answer of PE 68:", max(unlist(res), na.rm=TRUE), "\n")

This code run in less than 0.1 second.

> system.time(source("problem68.R"))
Answer of PE 68: 6531031914842725 
   user  system elapsed 
  0.097   0.000   0.096 
p5rn7vb

Related Posts

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>