5
5 3
2 4
3 1
4 5
 4
2 4
3 2
2 1
 5
5 3
2 4
3 1
4 5
 2
1 2
 4
3 4
2 3
3 1
 10
8 10
2 9
7 8
4 1
7 3
4 7
2 5
2 4
4 6
 5
3 4
3 2
3 1
1 5
 3
1 2
2 3
 5
1 2
1 3
1 4
1 5

1 2
2 3
2 4
 1 3
2 4
3 5
4 5
 1 2
 1 3
2 3
3 4
 1 4
2 4
2 5
2 9
3 7
4 6
4 7
7 8
8 10
 1 3
1 5
2 3
3 4
 1 2
2 3
 1 2
1 3
1 4
1 5

#include <bits/stdc++.h>
using namespace std;
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  int n;
  cin >> n;
  set<pair<int, int>> edges;
  int picked_number = 1;
  set<int> completely_unvisited;
  for (int i = 1; i <= n; ++i) {
    completely_unvisited.insert(i);
  }
  set<int> somewhat_visited;
  for (int i = (0); i < (n / 2 + n % 2); ++i) {
    if (edges.size() == n - 1 || picked_number == -1) {
      cout << "!" << endl;
      for (const auto& p : edges) {
        cout << p.first << " " << p.second << endl;
      }
      break;
    }
    cout << "? " << picked_number << endl;
    completely_unvisited.erase(picked_number);
    map<int, vector<int>> m;
    for (int i = (0); i < (n); ++i) {
      int dist;
      cin >> dist;
      m[dist].push_back(i + 1);
    }
    for (const auto& p : m) {
      int dist = p.first;
      const vector<int>& nodes = p.second;
      if (m.find(dist + 1) == m.end()) {
        break;
      }
      const vector<int>& next_nodes = m[dist + 1];
      if (nodes.size() == 1) {
        completely_unvisited.erase(nodes[0]);
        somewhat_visited.erase(nodes[0]);
        for (const auto& node : next_nodes) {
          edges.insert(make_pair(min(nodes[0], node), max(nodes[0], node)));
          somewhat_visited.insert(node);
        }
      }
    }
    picked_number = -1;
    for (const auto& node : completely_unvisited) {
      if (somewhat_visited.find(node) == somewhat_visited.end()) {
        picked_number = node;
        break;
      }
    }
    if (picked_number == -1) {
      picked_number = *completely_unvisited.begin();
    }
  }
}
