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;
    
    //                                 (POLICY BASED DS)
    // #include <ext/pb_ds/assoc_container.hpp>
    // #include <ext/pb_ds/tree_policy.hpp>
    // using namespace __gnu_pbds;
    // template<typename T>
    // using ordered_set=tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
    // template<typename T>
    // using ordered_multiset=tree<T,null_type,less_equal<T>,rb_tree_tag,tree_order_statistics_node_update>;
    //                      ( find_by_order( )  ,  order_of_key( ) )
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef vector<long long> vll;
    typedef pair<ll,ll> pll;
     
    const ll mod = 1e9 + 7;
    const ld PI = 3.1415926535897932384626;
    const ld eps = 1e-9;                            
     
    #define boost ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
    #define sidha(i,a,b) for(ll i=(ll)(a);i<(ll)(b);++i)
    #define ulta(i,a,b) for(ll i=(ll)(a);i>=(ll)(b);--i)
    #define stl(container,itr) \
        for(auto itr = container.begin(); itr != container.end(); itr++)
    #define sab(v) v.begin(), v.end()
    #define rall(v) v.rbegin(), v.rend()            
    #define test ll t;cin>>t;while(t--)
    #define sz size()
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define LOG2(X) (63ll - __builtin_clzll(X))
    
    #define modinv(x) powermod(x, mod-2)
    #define mktree(x) ll a,b; sidha(i,0,x){cin>>a>>b; adj[a].pb(b); adj[b].pb(a);}
    #define ncr(n,r) ( (n) >= (r) ? ((((fact[n]*modinv(fact[r]))%mod)*modinv(fact[n-(r)]))%mod) : (ll)0)
    #define MAX 400005
     
    ll powermod(ll x, ll y) { 
        ll ans=1;
        x=x%mod;
        while(y>0) { 
            if (y&1) 
                ans=(ans*x)%mod; 
            y=y>>1;
            x=(x*x)%mod; 
        } 
        return ans; 
    }
    
    ll power(ll x, ll y) { 
        ll ans=1;
        while(y>0) { 
            if (y&1) 
                ans=(ans*x); 
            y=y>>1;
            x=(x*x); 
        } 
        return ans; 
    }
    
    ll gcd(ll x,ll y){
       if(y==0) return x;
       return   gcd(y,x%y);
    }
    
    ll ceil(ll x,ll y){
        return ( (x/y)+(x%y!=0) );
    }
    
    vector<ll> adj[MAX];
    ll visit[MAX];
    void dfs(ll node){
        visit[node]=1;
        for(auto i : adj[node]){
            if(!visit[i]) dfs(i);
        }
    }
    
    // vll spf(MAX);
    // void sieve(){
    //     sidha(i,1,MAX)  spf[i]=i;
    //     for(ll i=4;i<MAX;i+=2)  spf[i]=2;
    //     for(ll i=3;i*i<=MAX;i++){
    //         if(spf[i]==i){
    //             for(ll j=i*i;j<MAX;j+=i){
    //                 if(spf[j]==j)   spf[j]=i;
    //             }
    //         }
    //     }
        
    //     // cnt[i] stores the number of prime factors which divides i
    //     // sidha(i,2,MAX){
    //     //     cnt[i]=cnt[i/spf[i]];
    //     //     if(spf[i/spf[i]]!=spf[i])   cnt[i]++;
    //     // }
    // }
    
    //                 avoid pow , ceil , max , directly with cout :)
    
    
    // #define endl '\n'
    
    int main()
    {
        boost;
        clock_t begin,end;
        begin=clock();
        
        ll n;
        cin>>n;
        ll arr[n],count=0,a,flag;
        set<pll> s;
        cout<<"? 1"<<endl;
        queue<ll> q;
        ll visit[n+1]={0};
        visit[1]=1;
        sidha(i,0,n){
            cin>>arr[i];
            if(arr[i]==1){
                s.insert({1,i+1});
            }
            else if(arr[i]>0){
                q.push(i+1);
            }
        }
        vector<pll > temp;
        while(1){
            if(s.sz==n-1)  break;
            flag=0;
            while(!q.empty()){
                a=q.front();
                q.pop();
                if(!visit[a]){
                    flag=1;
                    break;
                }
            }
            if(!flag)   break;
            cout<<"? "<<a<<endl;
            visit[a]=1;
            temp.clear();
            sidha(i,0,n){
                cin>>arr[i];
                if(arr[i]==1){
                    s.insert({min(a,i+1),max(a,i+1)});
                }
                else if(arr[i]>0 and visit[i+1]==0){
                    temp.pb(mp(arr[i],i+1));
                    // q.push(i+1);
                }
            }
            sort(sab(temp));
            for(auto i:temp)    q.push(i.se);
        }
        cout<<"!"<<endl;
        stl(s,itr){
            cout<<itr->fi<<" "<<itr->se<<endl;
        }
        
        end=clock();
        double tot_time=double(end-begin)/double(CLOCKS_PER_SEC);
        // cout<<"Time Taken: "<<fixed<<setprecision(3)<<tot_time;
        return 0;
    }
    