Created
January 1, 2017 20:05
-
-
Save notcome/6840291157587972b9930672581340d0 to your computer and use it in GitHub Desktop.
An example of how to employ modern syntactic sugars in writing ACM ICPC code.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// POJ 1093 | |
// This problem asks us to justify monospaced texts with a given width. | |
// For details, see http://poj.org/problem?id=1093. | |
let email = "Writing e-mails is fun, and with this program, they even look nice." | |
let width = 25 | |
let words = email.characters.split(separator: " ").map { String($0) } | |
let metrics: [Int] = words.map { $0.characters.count } | |
func square(_ x: Int) -> Int { | |
return x * x | |
} | |
struct Line { | |
let subrange: ClosedRange<Int> | |
let words: ArraySlice<String> | |
let metrics: ArraySlice<Int> | |
let gapCount: Int | |
let gapInfo: (basicGapWidth: Int, basicGapCount: Int, expandedGapCount: Int)? | |
let badness: Int | |
init?(words: [String], metrics: [Int], | |
subrange: ClosedRange<Int>, width: Int) { | |
self.subrange = subrange | |
self.words = words[subrange] | |
self.metrics = metrics[subrange] | |
guard subrange.count > 1 else { | |
self.gapCount = 0 | |
self.gapInfo = nil | |
self.badness = self.metrics.first! == width ? 0 : 500 | |
return | |
} | |
self.gapCount = subrange.count - 1 | |
let totalGapWidth = width - self.metrics.reduce(0) { $0 + $1 } | |
guard totalGapWidth >= gapCount else { return nil } | |
let basicGapWidth = totalGapWidth / gapCount | |
let expandedGapCount = totalGapWidth - basicGapWidth * gapCount | |
let basicGapCount = gapCount - expandedGapCount | |
self.gapInfo = (basicGapWidth, basicGapCount, expandedGapCount) | |
self.badness = basicGapCount * square(basicGapWidth - 1) + expandedGapCount * square(basicGapWidth) | |
} | |
var line: String { | |
guard let gapInfo = self.gapInfo else { return self.words[self.words.startIndex] } | |
var line = "" | |
let basicGap = String(repeating: " ", count: gapInfo.basicGapWidth) | |
let expandedGap = basicGap.appending(" ") | |
for i in 0..<self.gapCount { | |
let gap = i < gapInfo.basicGapCount ? basicGap : expandedGap | |
line.append(words[words.startIndex + i].appending(gap)) | |
} | |
line.append(self.words[self.words.endIndex - 1]) | |
return line | |
} | |
} | |
var table = [(line: Line, badness: Int)]() | |
table.reserveCapacity(words.count) | |
for i in 0..<words.count { | |
var line: Line? | |
var minBadness = 0x0fffffff | |
for j in (0...i).reversed() { | |
guard let newLine = Line(words: words, metrics: metrics, subrange: j...i, width: width) | |
else { break } | |
let previousBadness = j > 0 ? table[j - 1].badness : 0 | |
let newBadness = newLine.badness + previousBadness | |
if newBadness < minBadness { | |
minBadness = newBadness | |
line = newLine | |
} | |
} | |
table.append((line!, minBadness)) | |
} | |
var index = table.count - 1 | |
var lines = [String]() | |
repeat { | |
let line = table[index].line | |
lines.append(line.line) | |
index = line.subrange.lowerBound - 1 | |
} while index > 0 | |
for line in lines.reversed() { | |
print(line) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment