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

import java.io.*;
import java.util.*;
import java.math.*;

public class D {
	public static void main(String[] args) throws IOException {

		/**/
		Scanner sc = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
		/*/
		Scanner sc = new Scanner(new BufferedReader(new InputStreamReader(new FileInputStream("src/d.in"))));
		/**/
		
		int n = sc.nextInt();
		sc.nextLine();
		int[][] dists = new int[n+1][n+1];
		System.out.println("? 1");
		System.out.flush();
		dists[1] = Arrays.stream(("0 "+sc.nextLine()).split(" ")).mapToInt(Integer::parseInt).toArray();
		ArrayList<Integer> samePar = new ArrayList<>();
		ArrayList<Integer> diffPar = new ArrayList<>();
		for (int i = 2; i <= n; ++i) {
			if (dists[1][i]%2==0)
				samePar.add(i);
			else
				diffPar.add(i);
		}
		boolean same = samePar.size()<=diffPar.size();
		ArrayList<String> edges = new ArrayList<>();
		if (same) {
			for (int i = 1; i <= n; ++i) {
				if (dists[1][i] == 1) {
					edges.add(1+" "+i);
				}
			}
			for (int u : samePar) {
				System.out.println("? "+u);
				System.out.flush();
				dists[u] = Arrays.stream(("0 "+sc.nextLine()).split(" ")).mapToInt(Integer::parseInt).toArray();
				for (int v = 1; v <= n; ++v) {
					if (dists[u][v] == 1) {
						edges.add(u+" "+v);
					}
				}
			}
		} else {
			for (int u : diffPar) {
				System.out.println("? "+u);
				System.out.flush();
				dists[u] = Arrays.stream(("0 "+sc.nextLine()).split(" ")).mapToInt(Integer::parseInt).toArray();
				for (int v = 1; v <= n; ++v) {
					if (dists[u][v] == 1) {
						edges.add(u+" "+v);
					}
				}
			}
		}
		System.out.println("!");
		for (String s : edges)
			System.out.println(s);
		System.out.flush();
	}
}