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;
vector<long long> x;
long long s;
vector<long long> query(long long a) {
  cout << "? " << a << "\n";
  cout.flush();
  vector<long long> z;
  z.push_back(0);
  for (long long j = 0; j < s; j++) {
    long long k;
    cin >> k;
    z.push_back(k);
  }
  return z;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  long long a;
  cin >> a;
  s = a;
  long long tree[a + 1][a + 1];
  for (long long j = 0; j < a + 1; j++) {
    for (long long k = 0; k < a + 1; k++) {
      tree[j][k] = 0;
    }
  }
  x = query(1);
  vector<long long> q;
  q = x;
  vector<pair<long long, long long> > edge;
  vector<long long> found(a + 1, false);
  found[1] = true;
  for (long long j = 1; j < x.size(); j++) {
    if (x[j] == 1) {
      tree[1][j] = 1;
      tree[j][1] = 1;
      if (a == 2) {
        found[2] = true;
      }
    }
  }
  priority_queue<pair<long long, long long> > y;
  for (long long j = 1; j < x.size(); j++) {
    y.push({x[j], j});
  }
  while (!y.empty()) {
    pair<long long, long long> p = y.top();
    y.pop();
    if (found[p.second]) {
      continue;
    }
    x = query(p.second);
    long long par = -1;
    for (long long j = 1; j < a + 1; j++) {
      if (x[j] == 1 && (q[j] < q[p.second])) {
        found[j] = true;
        par = j;
        break;
      }
    }
    tree[p.second][par] = 1;
    tree[par][p.second] = 1;
    for (long long j = 1; j < a + 1; j++) {
      if (x[j] == 2 && (q[j] <= q[p.second])) {
        tree[par][j] = 1;
        tree[j][par] = 1;
        if (q[j] == q[p.second]) {
          found[j] = true;
        }
      }
    }
  }
  cout << "!\n";
  for (long long j = 1; j < a + 1; j++) {
    for (long long k = j + 1; k < a + 1; k++) {
      if (tree[j][k]) {
        cout << j << " " << k << "\n";
      }
    }
  }
  cout.flush();
  return 0;
}
