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;
const long long MOD = 1e9 + 7;
const int iinf = 1 << 29;
const long long llinf = 1ll << 60;
const double PI = 3.14159265;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
long long mrand(long long B) { return (unsigned long long)rng() % B; }
long long cross(pair<long long, long long> p1, pair<long long, long long> p2) {
  return p1.first * p2.second - p2.first * p1.second;
}
bool online(pair<long long, long long> a, pair<long long, long long> b,
            pair<long long, long long> c) {
  pair<long long, long long> p1{b.first - a.first, b.second - a.second};
  pair<long long, long long> p2{c.first - a.first, c.second - a.second};
  return cross(p1, p2) == 0;
}
void z_func(vector<int> &z, vector<int> &s, int n) {
  int L = 0, R = 0;
  for (int i = 1; i < n; i++) {
    if (i > R) {
      L = R = i;
      while (R < n && s[R - L] == s[R]) R++;
      z[i] = R - L;
      R--;
    } else {
      int k = i - L;
      if (z[k] < R - i + 1)
        z[i] = z[k];
      else {
        L = i;
        while (R < n && s[R - L] == s[R]) R++;
        z[i] = R - L;
        R--;
      }
    }
  }
}
inline long long ceil(long long x, long long y) { return (x + y - 1LL) / y; }
int n;
vector<pair<int, int>> ans;
void ask(int node, vector<int> &ret) {
  cout << "? " << node << endl;
  for (int i = 1; i <= n; i++) cin >> ret[i];
}
void solve(int node, int dist_to_par, vector<int> &pr) {
  vector<int> ret(n + 1);
  ask(node, ret);
  vector<bool> interest(n + 1, false);
  for (int i = 1; i <= n; i++) {
    if (pr[i] == ret[i] + dist_to_par) interest[i] = true;
  }
  vector<int> nseen(n + 1, 0);
  for (int i = 1; i <= n; i++) {
    if (!interest[i]) continue;
    nseen[ret[i]]++;
  }
  int first_bif = -1;
  for (int i = 1; i <= n; i++) {
    if (nseen[i] >= 2) {
      first_bif = i;
      break;
    }
  }
  vector<int> node_with_dist(n + 1, -1);
  for (int i = 2; i <= n; i++) {
    if (!interest[i]) continue;
    if ((ret[i] < first_bif || first_bif == -1) && ret[i]) {
      node_with_dist[ret[i]] = i;
    }
  }
  int last_node = node;
  for (int i = 1; (first_bif != -1 && i < first_bif) ||
                  (first_bif == -1 && node_with_dist[i] != -1);
       i++) {
    if (((int)(ans).size()) >= n - 1) return;
    ans.push_back({last_node, node_with_dist[i]});
    last_node = node_with_dist[i];
  }
  for (int i = 1; i <= n && ((int)(ans).size()) < n - 1; i++) {
    if (!interest[i]) continue;
    if (ret[i] == first_bif) {
      ans.push_back({last_node, i});
      if (((int)(ans).size()) >= n - 1) break;
      solve(i, ret[i], ret);
    }
  }
}
void work() {
  cin >> n;
  vector<int> ret(n + 1);
  ask(1, ret);
  int first_repeat = -1;
  vector<int> nseen(n + 1, 0);
  for (int i = 1; i <= n; i++) nseen[ret[i]]++;
  int first_bif = iinf;
  for (int i = 1; i <= n; i++) {
    if (nseen[i] >= 2) {
      first_bif = i;
      break;
    }
  }
  vector<int> node_with_dist(n + 1, -1);
  for (int i = 2; i <= n; i++) {
    if (ret[i] < first_bif && ret[i]) {
      node_with_dist[ret[i]] = i;
    }
  }
  int last_node = 1;
  for (int i = 1; i < first_bif && ((int)(ans).size()) < n - 1; i++) {
    ans.push_back({last_node, node_with_dist[i]});
    last_node = node_with_dist[i];
  }
  for (int i = 2; i <= n && ((int)(ans).size()) < n - 1; i++) {
    if (ret[i] == first_bif) {
      ans.push_back({last_node, i});
      if (((int)(ans).size()) >= n - 1) break;
      solve(i, ret[i], ret);
    }
  }
  cout << "!\n";
  for (auto &p : ans) cout << p.first << ' ' << p.second << '\n';
  cout << endl;
}
int main() {
  ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  work();
  return 0;
}
