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

/**
 *   Author: aksayushx
**/
#include<bits/stdc++.h>
#define F       first
#define S       second
#define all(a)  a.begin(),a.end()
#define sz(x)   (long long)x.size()
#define pb      push_back
#define mp      make_pair
#define mod     1'000'000'007
#define MOD     998244353
#define pi      3.141592653589793238462
#define setp(x) fixed<<setprecision(x)
#define deb(x)  cerr<<#x<<"="<<x<< '\n'
using namespace std;
typedef long long ll;
typedef long double ld;

ll power(ll x,ll y,ll m);
ll modInverse(ll n,ll m);
ll nCr(ll n,ll r,ll m);
ll ceiling(ll x,ll y);

bool sortbyth(const tuple<ll,int,int>& a, const tuple<ll,int,int>& b)
{
    // Descending by first, ascending by second
    if(get<0>(a)!=get<0>(b)) return get<0>(a)>get<0>(b);
    else return get<1>(a)<get<1>(b); 
}

int dx[]={-1,-1,-1,0,1,1,1,0};
int dy[]={-1,0,1,1,1,0,-1,-1};




void aksayushx()
{
    int n;
    cin>>n;
    vector<pair<int,int>> edges;
    vector<int> d(n);
    function<void(int)> query=[&](int x)
    {
        cout<<"? "<<x+1<<'\n';
        cout.flush();
        for(int i=0;i<n;i++)
            cin>>d[i];
        for(int i=0;i<n;i++)
        {
            if(d[i]==1)
                edges.pb({min(x+1,i+1),max(x+1,i+1)});
        }
    };
    query(0);
    vector<int> used=d;
    int odd=0,even=0;
    for(int i=0;i<n;i++)
    {
        if(d[i]%2==1) odd++;
        else even++;
    }
    int rem=odd<even?1:0;
    for(int i=1;i<n;i++)
    {
        if(used[i]%2==rem)
            query(i);
    }
    sort(all(edges));
    edges.erase(unique(all(edges)),edges.end());
    cout<<"!\n";
    for(auto e:edges)
        cout<<e.F<<' '<<e.S<<'\n';
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    #ifdef AKSAYUSHX
    (void)!freopen("input.txt","r",stdin);
    (void)!freopen("output.txt","w",stdout);
    (void)!freopen("error.txt","w",stderr);
    #endif
    int t=1;
    //cin>>t;
    while(t--)
        aksayushx();
    return 0;
}




// Returns x raised to the power y modulo mod
ll power(ll x, ll y, ll m)  
{  
    ll res = 1; 
    x = x % m;
    if (x == 0) return 0;
    while (y > 0)  
    {  
        if (y & 1)  
            res = (res*x) % m;  
        y = y>>1; 
        x = (x*x) % m;  
    }  
    return res;  
}

ll modInverse(ll n,ll m) 
{ 
    return power(n, m-2,m); 
}

ll ceiling(ll x,ll y)
{
    return (x+y-1)/y;
}