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.*;

public class D{
	public static void main(String[] args) throws IOException {
		// br = new BufferedReader(new FileReader(".in"));
		// out = new PrintWriter(new FileWriter(".out"));
		//new Thread(null, new (), "peepee", 1<<28).start();
		// Guess numbers exactly two away 
		
		int n = readInt();
		int t = (n+1)/2;
		t--;
		HashSet<Integer>[] adj = new HashSet[n+10];
		for (int i = 0; i < adj.length; i++) adj[i] = new HashSet<Integer>();
		boolean[] vis = new boolean[n+10];
		ArrayDeque<Integer> queries = new ArrayDeque<Integer>();
		// Okay, use your first query to determine bipartiteness. 
		System.out.println("? " + 1);
		System.out.flush();
		List<Integer> odds = new ArrayList<Integer>(), evens = new ArrayList<Integer>();
		boolean isOdd = false;
		for (int i = 1; i <= n; i++) {
			int d = readInt();
			if (d == 1) {
				adj[1].add(i);
				adj[i].add(1);
				vis[i] = true;
			}
			if (d % 2 == 0) evens.add(i);
			else odds.add(i);
			if (d == 0) isOdd = d % 2 == 1;
		}
		if (odds.size() == evens.size()) {
			if (isOdd) queries.addAll(odds);
			else queries.addAll(evens);
		}
		else if (odds.size() < evens.size() && !isOdd) {
			Arrays.fill(vis, false);
			queries.addAll(odds);
		}
		else if (evens.size() < odds.size() && isOdd){
			Arrays.fill(vis, false);
			queries.addAll(evens);
		}
		for (int tq = 0; tq < t && !queries.isEmpty(); tq++) {
			int q = queries.poll();
			if  (q == 1) {
				tq--;
				continue;
			}
			if (vis[q]) continue;
			vis[q] = true;
			System.out.println("? " + q);
			System.out.flush();
			for  (int i =1 ;i <=n; i++) {
				int d = readInt();
				if (d == 1) {
					adj[q].add(i);
					adj[i].add(q);
					vis[i] =true;
				}
			}
		}
		System.out.println("!");
		for (int i = 1; i <= n; i++) {
			for (int x: adj[i]) {
				if (i < x) {
					System.out.println(i + " " + x);
				}
			}
		}
	}
	
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static StringTokenizer st = new StringTokenizer("");
	static String read() throws IOException{return st.hasMoreTokens() ? st.nextToken():(st = new StringTokenizer(br.readLine())).nextToken();}
	static int readInt() throws IOException{return Integer.parseInt(read());}
	static long readLong() throws IOException{return Long.parseLong(read());}
	static double readDouble() throws IOException{return Double.parseDouble(read());}
	
}