package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
type Node struct {
id int
depth int
free int
}
func main() {
in := bufio.NewReaderSize(os.Stdin, 1<<20)
out := bufio.NewWriterSize(os.Stdout, 1<<20)
defer out.Flush()
var n, d, k int
if _, err := fmt.Fscan(in, &n, &d, &k); err != nil {
return
}
if d+1 > n {
out.WriteString("NO\n")
return
}
u := make([]int, 0, n-1)
v := make([]int, 0, n-1)
q := make([]Node, 0, n)
ok := true
for i := 1; i <= d+1; i++ {
if i > 1 {
u = append(u, i-1)
v = append(v, i)
}
deg := 1
if i != 1 && i != d+1 {
deg = 2
}
if deg > k {
ok = false
}
left := i - 1
right := d - (i - 1)
rem := left
if right < rem {
rem = right
}
free := k - deg
if rem > 0 && free > 0 {
q = append(q, Node{i, rem, free})
}
}
if !ok {
out.WriteString("NO\n")
return
}
used := d + 1
nextID := d + 2
head := 0
childFree := k - 1
for head < len(q) && used < n {
cur := q[head]
head++
childDepth := cur.depth - 1
for c := 0; c < cur.free && used < n; c++ {
id := nextID
nextID++
used++
u = append(u, cur.id)
v = append(v, id)
if childDepth > 0 && childFree > 0 {
q = append(q, Node{id, childDepth, childFree})
}
}
}
if used < n {
out.WriteString("NO\n")
return
}
out.WriteString("YES\n")
for i := 0; i < len(u); i++ {
out.WriteString(strconv.Itoa(u[i]))
out.WriteByte(' ')
out.WriteString(strconv.Itoa(v[i]))
out.WriteByte('\n')
}
}