#include <bits/stdc++.h>
using namespace std;
using lint = long long;
const int inf = 1000000007;
const int MOD = 1000000007;
struct Node {
  int no;
  int par;
  int dist;
  bool flag;
  vector<Node*> child;
  void build(int i) {
    no = i;
    dist = 0;
    par = i;
    flag = true;
  }
};
int saki = 0;
struct Tree {
  int n;
  vector<Node> node;
  map<pair<int, int>, int> edge;
  Tree(int k) {
    n = k;
    node.resize(n + 1);
    for (int i = 1; i <= n; ++i) {
      node[i].build(i);
    }
  }
  void add_edge(int a, int b) {
    node[a].child.push_back(&node[b]);
    node[b].child.push_back(&node[a]);
    edge[{a, b}] += 1;
    edge[{b, a}] += 1;
  }
  void BFS(int s) {
    for (int i = 1; i <= n; ++i) node[i].build(i);
    queue<Node> que;
    que.push(node[s]);
    while (!que.empty()) {
      Node buf = que.front();
      que.pop();
      int num = buf.child.size();
      for (int i = 0; i < num; ++i) {
        if (buf.child[i]->no != buf.par) {
          buf.child[i]->par = buf.no;
          buf.child[i]->dist = buf.dist + 1;
          que.push(*buf.child[i]);
        }
      }
    }
  }
  void DFS(Node& node, int& add) {
    if (!node.flag) return;
    if (node.child.size() == 1 && node.par != node.no) {
      if (add <= 0) return;
      add--;
      add_edge(node.no, saki);
      saki = node.no;
      edge.erase({node.no, node.par});
      edge.erase({node.par, node.no});
      return;
    } else {
      int num = node.child.size();
      for (int i = 0; i < num; ++i) {
        if (add == 0) return;
        if (node.child[i]->no != node.par) {
          if (node.child[i]->flag) DFS(*node.child[i], add);
        }
      }
      if (add <= 0) return;
      add--;
      add_edge(node.no, saki);
      saki = node.no;
      edge.erase({node.no, node.par});
      edge.erase({node.par, node.no});
    }
  }
};
signed main() {
  int n, d, k;
  cin >> n >> d >> k;
  if (d >= n) {
    cout << "NO" << endl;
    return 0;
  }
  Tree tree(n + 10);
  for (int i = 0; i < k; ++i) {
    if (2 + i > n) break;
    tree.add_edge(1, 2 + i);
  }
  int nxt = k + 2;
  for (int i = 2; i <= n; ++i) {
    if (nxt > n) break;
    for (int xx = 0; xx < k - 1; ++xx) {
      if (nxt > n) break;
      tree.add_edge(i, nxt);
      ++nxt;
    }
  }
  tree.BFS(1);
  int mxind = 0;
  int mx = 0;
  for (int i = 1; i <= n; ++i) {
    if (mx < tree.node[i].dist) {
      mx = tree.node[i].dist;
      mxind = i;
    }
  }
  tree.BFS(mxind);
  mx = 0;
  mxind = 0;
  for (int i = 1; i <= n; ++i) {
    if (mx < tree.node[i].dist) {
      mx = tree.node[i].dist;
      mxind = i;
    }
  }
  saki = mxind;
  if (mx > d) {
    cout << "NO" << endl;
    return 0;
  } else if (mx < d) {
    int add = d - mx;
    tree.node[mxind].flag = false;
    Node* nodep = &tree.node[mxind];
    while (nodep->no != nodep->par) {
      tree.node[nodep->par].flag = false;
      nodep = &tree.node[nodep->par];
    }
    queue<Node*> que;
    for (int i = 1; i <= n; ++i) {
      if (!tree.node[i].flag) {
        for (auto& val : tree.node[i].child) {
          if (val->flag) que.push(val);
        }
      }
    }
    while (!que.empty() && add > 0) {
      tree.DFS(*que.front(), add);
      que.pop();
    }
  }
  map<pair<int, int>, int> used;
  if (true) {
    int cnt = 0;
    cout << "YES" << endl;
    for (auto& val : tree.edge) {
      if (used.find(val.first) != used.end()) continue;
      cout << val.first.first << " " << val.first.second << "\n";
      used[{val.first.second, val.first.first}] += 1;
      ++cnt;
    }
  }
  return 0;
}
