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

/*
    JAI MATA DI
 */

import java.util.*;

import java.io.*;
import java.math.BigInteger;
import java.sql.Array;


public class Main {
	  static class FR{
			BufferedReader br;
			StringTokenizer st;
			public FR() {
				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; 
		    } 
		}
	 static long mod  = 1000000007;
	 static long gcd(long a, long b)
	  {      
	     if (b == 0)
	        return a;
	     return gcd(b, a % b); 
	  }
	static void sort(long[] arr ) {
		 ArrayList<Long> al = new ArrayList<>();
		 for(long e:arr) al.add(e);
		 Collections.sort(al);
		 for(int i = 0 ; i<al.size(); i++) arr[i] = al.get(i);
	 }
	static void sort(int[] arr ) {
		 ArrayList<Integer> al = new ArrayList<>();
		 for(int e:arr) al.add(e);
		 Collections.sort(al);
		 for(int i = 0 ; i<al.size(); i++) arr[i] = al.get(i);
	 }
	static int UB(long[] arr , long find , int l , int r) {
		while(l<=r) {
			int m = (l+r)/2;
			if(arr[m]<find) l = m+1;
			else r = m-1;
		}
		return l;
	}
	static int LB(long[] arr , long find,int l ,int r ) {
		while(l<=r) {
			int m = (l+r)/2;
			if(arr[m] > find) r = m-1;
			else l = m+1;
		}
		return r;
	}
	static int UB(int[] arr , long find , int l , int r) {
		while(l<=r) {
			int m = (l+r)/2;
			if(arr[m]<find) l = m+1;
			else r = m-1;
		}
		return l;
	}
	static int LB(int[] arr , long find,int l ,int r ) {
		while(l<=r) {
			int m = (l+r)/2;
			if(arr[m] > find) r = m-1;
			else l = m+1;
		}
		return r;
	}
	 static boolean[] prime(int num) {
			boolean[] bool = new boolean[num];
		     
		      for (int i = 0; i< bool.length; i++) {
		         bool[i] = true;
		      }
		      for (int i = 2; i< Math.sqrt(num); i++) {
		         if(bool[i] == true) {
		            for(int j = (i*i); j<num; j = j+i) {
		               bool[j] = false;
		            }
		         }
		      }
		      if(num >= 0) {
		    	  bool[0] = false;
		    	  bool[1] = false;
		      }
		      
		      return bool;
		}

	 static int ncr(int n, int k)
	    {
	        long C[][] = new long[n + 1][k + 1];
	        int i, j;
	 
	        // Calculate  value of Binomial
	        // Coefficient in bottom up manner
	        for (i = 0; i <= n; i++) {
	            for (j = 0; j <= Math.min(i, k); j++) {
	                // Base Cases
	                if (j == 0 || j == i)
	                    C[i][j] = 1;
	 
	                // Calculate value using
	                // previously stored values
	                else
	                    C[i][j] = (C[i - 1][j - 1] + C[i - 1][j])%mod;
	            }
	        }
	 
	        return (int)C[n][k];
	    }

/* ***************************************************************************************************************************************************/	 
	 static FR sc = new FR();
	 static StringBuilder sb = new StringBuilder();
	 public static void main(String args[]) {
//		 int tc = sc.nextInt();
		 int tc = 1;
		 
		 while(tc-->0) {
				
			 TEST_CASE();
		 }
	    System.out.println(sb);
	 }
	 static void TEST_CASE() {
		 int n = sc.nextInt();
		 
		 boolean[] connect = new boolean[n+1];
		 LinkedList<Integer> ll = new LinkedList<Integer>();
		 
		 for(int i = 1 ; i<=n ; i++)
			 ll.add(i);
		 
		 ArrayList<ArrayList<Integer>> adj = new ArrayList<ArrayList<Integer>>();
		 for(int i = 0 ; i<=n ; i++) adj.add(new ArrayList<Integer>());
		 
		 while(!ll.isEmpty()) {
			 int ind = ll.remove();
			 if(connect[ind]) continue;
			 System.out.println("? "+ind);
			 System.out.flush();
			 int[] arr = new int[n+1];
			 int max = 0;
			 for(int i = 1 ; i<=n  ;i++) {
				 arr[i] = sc.nextInt();
				 max = Math.max(max, arr[i]);
			 }
			 ArrayList<ArrayList<Integer>> dis = new ArrayList<ArrayList<Integer>>();
			 for(int i = 0 ; i<=max ; i++) dis.add(new ArrayList<Integer>());
			 for(int i = 1 ; i<=n ; i++) {
				 dis.get(arr[i]).add(i);
			 }
//			 System.out.println(dis);
			 for(int i = 0 ; i <max ; i++) {
				 if(dis.get(i).size() == 1) {
					 int p = dis.get(i).get(0);
					 for(int c:dis.get(i+1)) {
						 if(!connect[c] || !connect[p]) {
							 connect[c] = true;
							 connect[p] = true;
							 adj.get(p).add(c);
						 }
					 }
					 
				 }
			 }
		 }
		 System.out.println("!");
		 for(int i = 1 ; i<=n ;i++) {
			 for(int c:adj.get(i)) {
				 System.out.println(i+" "+c);
			 }
		 }
	 }

	
}














