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;
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
#define lli long long int
//#define ordered_set tree<lli, null_type,less<lli>, rb_tree_tag,tree_order_statistics_node_update>
//change data type as per problem (not in vscode)
#define INF 1000000000000000000
#define llu unsigned long long int
#define pb push_back
#define ff first
#define vl vector<pair<lli,lli>>
#define ss second
lli N;
set<pair<lli,lli>> s;
vector<lli> query(int n)
{
    cout<<"? "<<n<<endl;
    int i;
    vector<lli> ans(N+1);
    for(i=0;i<N;i++)
    {
        cin>>ans[i];
        if(ans[i]==1)
        s.insert({min((i+1),n),max(n,(i+1))});
    }
    return ans;
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
lli t=1,n,i;
//cin>>t;
while(t--)
{
    cin>>N;
    vector<lli> v;
    v=query(1);
    lli odd=0,even=0;
    for(i=1;i<N;i++)
    if(v[i]&1)
    odd++;
    else
    even++;
    lli p;
    if(odd>even)
    p=0;
    else
    p=1;
    for(i=1;i<N;i++)
    {
        if(v[i]%2==p)
        vector<lli> k=query(i+1);
    }
    cout<<"!"<<endl;
    for(auto &x: s)
    cout<<x.ff<<" "<<x.ss<<endl;
}
}