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;
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
struct VectorHash {
  size_t operator()(const std::vector<int> &v) const {
    std::hash<int> hasher;
    size_t seed = 0;
    for (int i : v) {
      seed ^= hasher(i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }
    return seed;
  }
};
void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\'' << x << '\''; }
void __print(const char *x) { cerr << '\"' << x << '\"'; }
void __print(const string &x) { cerr << '\"' << x << '\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }
template <typename T, typename V>
void __print(const pair<T, V> &x) {
  cerr << '{';
  __print(x.first);
  cerr << ',';
  __print(x.second);
  cerr << '}';
}
template <typename T>
void __print(const T &x) {
  int f = 0;
  cerr << '{';
  for (auto &i : x) cerr << (f++ ? "," : ""), __print(i);
  cerr << "}";
}
void _print() { cerr << "]\n"; }
template <typename T, typename... V>
void _print(T t, V... v) {
  __print(t);
  if (sizeof...(v)) cerr << ", ";
  _print(v...);
}
long long int cnt[2005];
bool vis[2005];
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  long long int n;
  cin >> n;
  vector<long long int> a(n + 1);
  queue<long long int> q;
  q.push(1);
  vis[1] = 1;
  vector<pair<long long int, long long int>> ans, t;
  while (!q.empty() and ans.size() < n - 1) {
    long long int node = q.front();
    q.pop();
    t.clear();
    cout << "? " << node << endl;
    for (int i = 1; i <= n; i++) {
      cin >> a[i];
      if (!vis[i]) {
        t.push_back({a[i], i});
      }
    }
    sort(t.begin(), t.end());
    long long int ind = -1;
    for (int i = 1; i < t.size(); i++) {
      ;
      if (t[i].first != t[i - 1].first) {
        ans.push_back({node, t[i - 1].second});
        node = t[i - 1].second;
        vis[node] = 1;
        ;
      } else {
        ind = i - 1;
        break;
      }
    }
    if (ind == -1) ans.push_back({node, t[t.size() - 1].second});
    ;
    if (t.size() > 1) {
      for (int i = ind; i < t.size() - 1; i++) {
        if (t[i].first == t[i + 1].first) {
          ans.push_back({node, t[i].second});
          vis[t[i].second] = 1;
          q.push(t[i].second);
          ind += 1;
        } else {
          break;
        }
      }
      if (t[ind].first == t[ind - 1].first) {
        ans.push_back({node, t[ind].second});
        vis[t[ind].second] = 1;
        q.push(t[ind].second);
      }
    }
  }
  cout << "!" << endl;
  for (auto i : ans) {
    cout << i.first << " " << i.second << endl;
  }
}
