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;
template <typename T1, typename T2>
inline void chkmin(T1 &a, T2 b) {
  if (a > b) a = b;
}
template <typename T1, typename T2>
inline void chkmax(T1 &a, T2 b) {
  if (a < b) a = b;
}
using ll = long long;
using ld = long double;
const string FILENAME = "input";
const int Mod = 998244353;
int sum(int a, int b) { return (a + b >= Mod ? a + b - Mod : a + b); }
int mul(int a, int b) { return ((ll)a * b) % Mod; }
int powm(int a, int b) {
  int res = 1;
  while (b) {
    if (b & 1) {
      res = mul(res, a);
    }
    a = mul(a, a);
    b >>= 1;
  }
  return res;
}
int inv(int a) { return powm(a, Mod - 2); }
const int MAXN = 2005;
int n;
vector<int> d[MAXN];
vector<int> myquery(int x) {
  if (!d[x].empty()) {
    return d[x];
  }
  cout << "? " << x + 1 << endl;
  vector<int> dists;
  dists.resize(n);
  for (int i = 0; i < n; i++) {
    cin >> dists[i];
  }
  return dists;
}
vector<pair<int, int> > who[MAXN];
vector<pair<int, int> > ans;
vector<int> kd[MAXN];
void build(int u) {
  if (who[u].empty()) {
    return;
  }
  for (int i = 0; i <= n; i++) {
    kd[i].clear();
  }
  kd[0].push_back(u);
  for (int i = 0; i < (int)(who[u]).size(); i++) {
    kd[who[u][i].first].push_back(who[u][i].second);
  }
  for (int i = 1; i < n; i++) {
    if (kd[i].empty()) {
      break;
    }
    if ((int)(kd[i - 1]).size() == 1) {
      for (auto h : kd[i]) {
        ans.push_back(make_pair(kd[i - 1][0], h));
      }
    } else {
      if ((int)(kd[i]).size() < (int)(kd[i - 1]).size()) {
        for (auto h : kd[i]) {
          d[h] = myquery(h);
        }
        for (auto h : kd[i]) {
          for (auto h1 : kd[i - 1]) {
            if (d[h][h1] == 1) {
              ans.push_back(make_pair(h1, h));
            }
          }
        }
      } else {
        for (auto h : kd[i - 1]) {
          d[h] = myquery(h);
        }
        for (auto h : kd[i]) {
          for (auto h1 : kd[i - 1]) {
            if (d[h1][h] == 1) {
              ans.push_back(make_pair(h1, h));
            }
          }
        }
      }
    }
  }
}
void solve() {
  cin >> n;
  d[0] = myquery(0);
  int a = 0;
  int b = 1;
  for (int i = 1; i < n; i++) {
    if (d[a][i] > d[a][b]) {
      b = i;
    }
  }
  d[b] = myquery(b);
  vector<pair<int, int> > mid;
  for (int i = 0; i < n; i++) {
    if (i != a && i != b) {
      if (d[a][i] + d[b][i] == d[a][b]) {
        mid.push_back(make_pair(d[a][i], i));
      }
    }
  }
  sort((mid).begin(), (mid).end());
  vector<int> diam;
  diam.push_back(a);
  for (auto x : mid) {
    diam.push_back(x.second);
  }
  diam.push_back(b);
  for (int i = 0; i < (int)(diam).size() - 1; i++) {
    ans.push_back(make_pair(diam[i], diam[i + 1]));
  }
  for (int i = 0; i < n; i++) {
    if (i != a && i != b) {
      if (d[a][i] + d[b][i] > d[a][b]) {
        int x = (d[a][i] + d[b][i] - d[a][b]) / 2;
        int pos = d[a][i] - x;
        who[diam[pos]].push_back(make_pair(x, i));
      }
    }
  }
  for (int i = 0; i < (int)(diam).size(); i++) {
    build(diam[i]);
  }
  cout << "!" << endl;
  for (auto x : ans) {
    cout << x.first + 1 << ' ' << x.second + 1 << endl;
  }
}
int main() {
  ios_base::sync_with_stdio(false);
  int t;
  t = 1;
  while (t--) {
    solve();
  }
  return 0;
}
