← Home
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')
	}
}