Based on Knuth's algorithm