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>
using namespace __gnu_pbds;
using namespace std;
 
#define ff              first
#define all(x)            (x).begin(),(x).end()
#define ss              second
#define int              long long 
#define pb              push_back
#define mp              make_pair
#define pii             pair<int,int>
#define vi              vector<int>
#define mii             map<int,int>
#define pqb             priority_queue<int>
#define pqs             priority_queue<int,vi,greater<int> >
#define setbits(x)      __builtin_popcountll(x)
#define zrobits(x)      __builtin_ctzll(x)
#define mod             1000000007
#define inf             1e18
#define ps(x,y)         fixed<<setprecision(y)<<x
#define mk(arr,n,type)  type *arr=new type[n];
#define w(x)            int x; cin>>x; while(x--)
mt19937                 rng(chrono::steady_clock::now().time_since_epoch().count());
 
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;
template<typename T1,typename T2>istream& operator>>(istream& in,pair<T1,T2> &a){in>>a.fr>>a.sc;return in;}
template<typename T1,typename T2>ostream& operator<<(ostream& out,pair<T1,T2> a){out<<a.fr<<" "<<a.sc;return out;}
template<typename T,typename T1>T amax(T &a,T1 b){if(b>a)a=b;return a;}
template<typename T,typename T1>T amin(T &a,T1 b){if(b<a)a=b;return a;} 
int expo(int a, int b, int mod1) {int res = 1; while (b > 0) {if (b & 1)res = (res * a) % mod1; a = (a * a) % mod1; b = b >> 1;} return res;}
 
void a_d_c()
{
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif

}
	set<int> s1;
	vector<pii> s2;
	
    int n;
void check(int ks,vi temp)
{	
	if(s1.size()==1)
	{
		for(int i=ks-1;i>=0;i--)
		{
			if(temp[i]==1)
			{
				s2.pb({ks,i+1});
				s1.erase(ks);
				return;
			}
		}
	}
	s1.erase(ks);
	cout<<"?"<<" "<<ks<<endl;
	for(int i=0;i<n;i++)
		{
			cin>>temp[i];
		}
		for(int i=0;i<n;i++)
		{	if(temp[i]==1)
			{
				
				s2.pb({ks,i+1});
				s1.erase(i+1);
			}
			if(s1.find(i+1)!=s1.end())
			{
			
			if(temp[i]==2)
			{
				check(i+1,temp);
			}
			}
		}
		return;

}

void desired()
{
	cin>>n;

	for(int i=1;i<=n;i++)
	{
		s1.insert(i);
	}
	
	while(s1.size()>0)
	{
		int ks=*s1.begin();
		
		vi temp(n);
		check(ks,temp);
		
	
		

	}
	cout<<"!"<<endl;
	for(auto x:s2)
	{
		cout<<x.first<<" "<<x.second<<endl;

	}
	return;
} 
signed main()
{   
    a_d_c();
   
        desired();
    
    
     return 0;
}