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

/*
 * akshaygupta26
 */
import java.io.*;
import java.util.*;
public class D
{ 
	
	static class Triplet{
		int row,col,idx;
		Triplet(){}
		Triplet(int r,int c,int i){
			row=r;
			col=c;
			idx=i;
		}
	}
	
    public static void main(String[] args) 
	{ 
		FastReader sc=new FastReader(); 
		StringBuffer ans=new StringBuffer();
		int test=1;
		while(test-->0)
		{
			int n=sc.nextInt();
			boolean vis[]=new boolean[n+1];
			
			Queue<Integer> q=new LinkedList<>();
			q.add(1);
			int cnt=n-1;
			ArrayList<Integer> arr[]=new ArrayList[n+1];
			
			vis[1]=true;
			
			
			ArrayList<Integer> g[]=new ArrayList[n+1];
			for(int i=0;i<=n;i++) {
				arr[i]=new ArrayList<>();
				g[i]=new ArrayList<>();
			}
		
			
			
			while(cnt>0 && !q.isEmpty()) {
				int num =q.poll();
				
				System.out.println("? "+num);
				//flush here
				System.out.flush();
				
				for(int i=0;i<=n;i++) arr[i].clear();
				
				for(int i=1;i<=n;i++) {
					int dist =sc.nextInt();
					if(vis[i]) continue;
					arr[dist].add(i);
				}
				
				int dist=1;
				int par=num;
				while(true) {
					int sz=arr[dist].size();
					if(sz == 0) break;
					if(sz == 1) {
						if(vis[arr[dist].get(0)])break;
						g[par].add(arr[dist].get(0));
						vis[arr[dist].get(0)] =true;
						--cnt;
						par=arr[dist].get(0);
						dist++;continue;
					}
					else {
						for(int x:arr[dist]) {
							if(vis[x]) continue;
							g[par].add(x);
							q.add(x);
							vis[x]=true;
							--cnt;
						}
						break;
					}
				}	
			}
			
			
			System.out.println("!");
			for(int i=1;i<=n;i++)
			{
				for(int x:g[i]) {
					System.out.println(i+" "+x);
				}
			}
			
			System.out.flush();
			
		}
		
	    System.out.print(ans);
	} 
 
    static long _gcd(long a,long b) {
    	if(b == 0) return a;
    	return _gcd(b,a%b);
    }
    
    static final Random random=new Random();
    
	static void ruffleSort(int[] a) {
		int n=a.length;//shuffle, then sort 
		for (int i=0; i<n; i++) {
			int oi=random.nextInt(n), temp=a[oi];
			a[oi]=a[i]; a[i]=temp;
		}
		Arrays.sort(a);
	}
	
	static void ruffleSort(long[] a) {
		int n=a.length;//shuffle, then sort 
		for (int i=0; i<n; i++) {
			int oi=random.nextInt(n);
			long temp=a[oi];
			a[oi]=a[i]; a[i]=temp;
		}
		Arrays.sort(a);
	}
	
	static class FastReader 
	{ 
		BufferedReader br; 
		StringTokenizer st; 

		public FastReader() 
		{ 
			br = new BufferedReader(new
					InputStreamReader(System.in)); 
		} 

		String next() 
		{ 
			while (st == null || !st.hasMoreElements()) 
			{ 
				try
				{ 
					st = new StringTokenizer(br.readLine()); 
				} 
				catch (IOException e) 
				{ 
					e.printStackTrace(); 
				} 
			} 
			return st.nextToken(); 
		} 

		int nextInt() 
		{ 
			return Integer.parseInt(next()); 
		} 

		long nextLong() 
		{ 
			return Long.parseLong(next()); 
		} 

		double nextDouble() 
		{ 
			return Double.parseDouble(next()); 
		} 

		String nextLine() 
		{ 
			String str = ""; 
			try
			{ 
				str = br.readLine(); 
			} 
			catch (IOException e) 
			{ 
				e.printStackTrace(); 
			} 
			return str; 
		} 
	} 


} 
