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>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
///Welcome to Nasif's Code
#define bug printf("bug\n");
#define bug2(var) cout<<#var<<" "<<var<<endl;
#define co(q) cout<<q<<endl;
#define all(q) (q).begin(),(q).end()
#define pi acos(-1)
#define inf 1000000000000000LL
#define FastRead    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define MODADD(ADD_X,ADD_Y)  (ADD_X+ADD_Y)%MOD
#define MODSUB(SUB_X,SUB_Y)  ((SUB_X-SUB_Y)+MOD)%MOD
#define MODMUL(MUL_X,MUL_Y)  (MUL_X*MUL_Y)%MOD
#define LCM(LCM_X,LCM_Y) (LCM_X/__gcd(LCM_X,LCM_Y))*LCM_Y
template <typename T> using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
typedef long long int ll;
typedef unsigned long long int ull;
const int MOD = (int)1e9+7;
const int MAX = 1e6;
int dx[]= {1,0,-1,0,1,-1,1,-1};
int dy[]= {0,1,0,-1,1,-1,-1,1};
vector<pair<int,int> >ans;
int arr[MAX],n,vis[MAX];
int parent[MAX+50];
int root(int child)
{
    while(parent[child]!=child)
    {
        parent[child]=parent[parent[child]];
        child=parent[child];
    }
    return child;
}
void node_union(int x,int y)
{
    int a=root(x);
    int b=root(y);
    parent[min(a,b)]=parent[max(a,b)];
}

void ask(int src)
{
    cout<<"? "<<src<<endl;;
    vector<int>v[n+5];
    int sz[n+5]= {0};
    for(int i=1; i<=n; i++)
    {
        cin>>arr[i];
        v[arr[i]].push_back(i);
        sz[arr[i]]++;
    }
    for(int i=0; i<n; i++)
    {
        if(sz[i]==1)
        {
            int node=v[i][0];
            for(auto it:v[i+1])
            {
                int a=node,b=it;
                if(a>b)
                    swap(a,b);
                if(root(a)==root(b))
                    continue;
                node_union(a,b);
                ans.push_back({a,b});
                vis[it]=1;
            }
            vis[node]=1;
        }
        else
            break;
    }
}
int main()
{
    FastRead
    //freopen("output.txt", "w", stdout);
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        if(!vis[i])
            ask(i);
    }
    cout<<"!"<<endl;
    for(auto i:ans)
        cout<<i.first<<" "<<i.second<<endl;


    return 0;
}
