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;


#define     mod             (int)1e9+7
#define     MOD             998244353
#define     ll              long long
#define     int              long long
#define     mp              make_pair
#define     deb(x)          cout<< x << endl
#define     inf        1e18
#define     F               first
#define     S               second
#define     pb              push_back
#define     pf              emplace_front
#define     all(p)          p.begin(), p.end()
#define     rep(i,a,b)      for( i=a;i<b;++i)
#define     repr(i,a,b)     for( i=a;i>=b;i--)
#define     up              upper_bound
#define     lb              lower_bound
#define     t()             int test;cin>>test;while(test--)
#define     setbits(x)      __builtin_popcountll(x)
#define     si              set<int>
#define     que_max         priority_queue <int>
#define     que_min         priority_queue <int, vi, greater<int> >
#define     IOS             ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define     endl            "\n"
#define isOn(S, j)                   (S & (1 << j))
#define setBit(S, j)                 (S |= (1 << j))
#define clearBit(S, j)               (S &= ~(1 << j))
#define toggleBit(S, j)              (S ^= (1 << j))
#define lowBit(S)                    (S & (-S))
#define setAll(S, n)                 (S = (1 << n) - 1)
#define modulo(S, N)                 ((S) & (N - 1))
#define isPowerOfTwo(S)              (!(S & (S - 1)))
#define nearestPowerOfTwo(S)         ((int)pow(2.0, (int)((log((double)S) / log(2.0)) + 0.5)))
#define turnOffLastBit(S)            ((S) & (S - 1))
#define turnOnLastZero(S)            ((S) | (S + 1))
#define turnOffLastConsecutiveBits(S) ((S) & (S + 1))
#define turnOnLastConsecutiveZeroes(S) ((S) | (S - 1))

typedef pair<int, int>  pii;
typedef pair<ll, ll>  pl;
typedef vector<int>   vi;
typedef vector<ll>    vl;
typedef vector<pii>   vpii;
typedef vector<pl>    vpl;
typedef vector<vi>    vvi;
typedef vector<vl>    vvl;


#define TRACE
#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1) {
  cout << name << " : " << arg1 << endl;
  //use cerr if u want to display at the bottom
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args) {
  const char* comma = strchr(names + 1, ','); cout.write(names, comma - names) << " : " << arg1 << " | "; __f(comma + 1, args...);
}
#else
#define trace(...)
#endif
int mpow(int base, int exp);  
void ipgraph(int n, int m);
void dfs(int u, int par);

const int N = 100005, M = 100005;
//=======================

vl g[N];
int a[N];
ll n;
vl interact(ll r)
{
  cout<<"? "<<r<<endl;
  vl d(n+1);
  ll i;
  rep(i,1,n+1)
  cin>>d[i];
  return d;
}
void solve()
{
    ll i,j,m,k;
    cin>>n;
    if(n==1)
    {
      cout<<"! "<<endl;
      return;
    }
    int node=1;
    vl vis(n+1);
    set<pl> edge;
    vl arr=interact(node);
    ll odd=0,even=0;
    rep(i,1,n+1)
    {
      if(arr[i]==1)
        edge.insert({1,i});
      if(arr[i]%2)
        odd++;
      else
        even++;
    }
    // trace(odd,even);
    if(odd<even)
    {
      rep(i,2,n+1)
      {
        if(arr[i]%2==0)
          continue;
        vl tmp=interact(i);
        rep(j,1,n+1)
        {
          if(tmp[j]==1&&edge.find({j,i})==edge.end())
            edge.insert({i,j});
        }
      }
    }
    else
    {
       rep(i,2,n+1)
      {
        if(arr[i]%2)
          continue;
        vl tmp=interact(i);
        rep(j,1,n+1)
        {
          if(tmp[j]==1&&edge.find({j,i})==edge.end())
            edge.insert({i,j});
        }
      }
    }
    cout<<"! "<<endl;
    for(auto it:edge)
      cout<<it.F<<" "<<it.S<<endl;
}

int32_t main()
{
  // IOS;

  // t()
  {
       solve();
  }

}
int mpow(int base, int exp) {
  base %= (mod);
  int result = 1;
  while (exp > 0) {
    if (exp & 1) result = ((ll)result * base) % (mod);
    base = ((ll)base * base) % (mod);
    exp >>= 1;
  }
  return result;
}

void ipgraph(int n, int m){
  int i, u, v;
  while(m--){
    cin>>u>>v;
    u--, v--;
    g[u].pb(v);
    g[v].pb(u);
  }
}

void dfs(int u, int par){
  for(int v:g[u]){
    if (v == par) continue;
    dfs(v, u);
  }
}