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

from collections import Counter
import string
import math
import bisect
#import random
import sys
# sys.setrecursionlimit(10**6) 
from fractions import Fraction
def array_int():
    return [int(i) for i in sys.stdin.readline().split()]
def vary(arrber_of_variables):
    if arrber_of_variables==1:
        return int(sys.stdin.readline())
    if arrber_of_variables>=2:
        return map(int,sys.stdin.readline().split()) 
def makedict(var):
    return dict(Counter(var))
testcases=1
for _ in range(testcases):
    n=vary(1)
    print('? 1',flush=True)
    dis=array_int()
    tree=[[] for i in range(n+1)]
    nodes=[1]*(n+1)
    for i in range(len(dis)):
        if dis[i]%2!=0:
            if dis[i]==1:
                tree[1].append(i+1)
            nodes[i+1]=0
        else:
            nodes[i+1]=1
    white=nodes.count(0)
    black=nodes.count(1)-1
    if black<=white:
        for i in range(2,n+1):
            if nodes[i]==1:
                print('?',i,flush=True)
                dis=array_int()
                for j in range(len(dis)):
                    if dis[j]==1:
                        tree[i].append(j+1)
    else:
        for i in range(1,n+1):
            if nodes[i]==0:
                print('?',i,flush=True)
                dis=array_int()
                for j in range(len(dis)):
                    if dis[j]==1:
                        tree[i].append(j+1)
    print('!',flush=True)
    # print(tree)
    st=set()
    for i in range(1,n+1):
        for j in tree[i]:
            if (i,j) not in st and (j,i) not in st:
                print(i,j,flush=True)
                st.add((i,j))
                st.add((j,i))
    
    
            



