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

#########################################################################################################\
#########################################################################################################
###################################The_Apurv_Rathore#####################################################
#########################################################################################################
#########################################################################################################
import sys,os,io
from sys import stdin
from math import log, gcd, ceil
from collections import defaultdict, deque, Counter
from heapq import heappush, heappop, heapify
from bisect import bisect_left , bisect_right
import math 




alphabets = list('abcdefghijklmnopqrstuvwxyz')



#for deep recursion__________________________________________-
from types import GeneratorType
def bootstrap(f, stack=[]):
    def wrappedfunc(*args, **kwargs):
        if stack:
            return f(*args, **kwargs)
        else:
            to = f(*args, **kwargs)
            while True:
                if type(to) is GeneratorType:
                    stack.append(to)
                    to = next(to)
                else:
                    stack.pop()
                    if not stack:
                        break
                    to = stack[-1].send(to)
            return to

    return wrappedfunc

def ncr(n, r, p):  
    num = den = 1
    for i in range(r):
        num = (num * (n - i)) % p
        den = (den * (i + 1)) % p
    return (num * pow(den,p - 2, p)) % p

def primeFactors(n): 
    l = []
    while n % 2 == 0: 
        l.append(2)
        n = n / 2
    for i in range(3,int(math.sqrt(n))+1,2): 
        while n % i== 0: 
            l.append(int(i))
            n = n / i 
    if n > 2: 
        l.append(n)
    c = dict(Counter(l))
    return list(set(l))
    # return c

def power(x, y, p) : 
	res = 1
	x = x % p 
	if (x == 0) : 
		return 0
	while (y > 0) : 
		if ((y & 1) == 1) : 
			res = (res * x) % p 
		y = y >> 1	 # y = y/2 
		x = (x * x) % p 		
	return res 

#____________________GetPrimeFactors in log(n)________________________________________
def sieveForSmallestPrimeFactor():
    MAXN = 100001
    spf = [0 for i in range(MAXN)]
    spf[1] = 1
    for i in range(2, MAXN):
        spf[i] = i
    for i in range(4, MAXN, 2):
        spf[i] = 2
    for i in range(3, math.ceil(math.sqrt(MAXN))):
        if (spf[i] == i):
            for j in range(i * i, MAXN, i): 
                if (spf[j] == j):
                    spf[j] = i
    return spf
def getPrimeFactorizationLOGN(x):
    spf = sieveForSmallestPrimeFactor()
    ret = list()
    while (x != 1):
        ret.append(spf[x])
        x = x // spf[x]  
    return ret
#____________________________________________________________



def SieveOfEratosthenes(n): 
    #time complexity = nlog(log(n))
    prime = [True for i in range(n+1)]
    p = 2
    while (p * p <= n):
        if (prime[p] == True):
            for i in range(p * p, n+1, p):
                prime[i] = False
        p += 1
    return prime
def si():
    return input()
def divideCeil(n,x):
    if (n%x==0):
        return n//x
    return n//x+1
def ii():
    return int(input())
def li():
    return list(map(int,input().split()))

#__________________________TEMPLATE__________________OVER_______________________________________________________


# if(os.path.exists('input.txt')):
#     sys.stdin = open("input.txt","r") ; sys.stdout = open("output.txt","w") 
# else:
#     input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

def solve():
    n = ii()
    l = [defaultdict(lambda:0) for i in range(n+1)]
    print('?',1)
    dis = li()
    edges = []
    q = []
    disfrom0 = []

    dis1 = []
    dis2 = []
    for i in range(n):
        l[1][i+1]=dis[i]
        if dis[i]==1:
            dis1.append(i+1)
            edges.append([1,i+1])
        elif dis[i]==2:
            dis2.append(i+2)
            


    parent = 1    
    level = 1
    flag = 1
    if len(dis2)>=len(dis1):
        level = 1
        q.extend(dis1)
        flag = 1
    else:
        level = 2
        q.extend(dis2)
        flag = 2
    

    
    while(q):
        # print(q)
        if flag==2:
            length = len(q)
            for _ in range(length):
                node = q.pop(0)
                print('?',node)
                dis = li()
                nextnode = []
                nextnextnode = []
                for i in range(n):
                    if dis[i]==1 :
                        edges.append([node,i+1])
                    if dis[i]==1 and l[1][i+1]!=level-1:
                        nextnode.append(i+1)
                        # edges.append([node,i+1])
                    if dis[i]==2 and l[1][i+1]!=level-2:
                        nextnextnode.append(i+1)
                if len(nextnode)>len(nextnextnode):
                    level+=2
                    flag = 2
                    q.extend(nextnextnode)
                else:
                    level+=1
                    flag = 1
                    q.extend(nextnode)
        else:
            length = len(q)
            for _ in range(length):
                node = q.pop(0)
                print('?',node)
                dis = li()
                nextnode = []
                nextnextnode = []
                for i in range(n):
                    if dis[i]==1 and l[1][i+1]!=level-1:
                        nextnode.append(i+1)
                        edges.append([node,i+1])
                    if dis[i]==2 and l[1][i+1]!=level-2:
                        nextnextnode.append(i+1)
                if len(nextnode)>len(nextnextnode):
                    level+=2
                    flag = 2
                    q.extend(nextnextnode)
                else:
                    level+=1
                    flag = 1
                    q.extend(nextnode)
        for i in edges:
            print(*i)


                

    # while(q):
    #     length = len(q)
    #     for _ in range(length):
    #         if flag==
            # node = q.pop(0)
            # print('?',node)
            # dis = li()
            # for i in range(n):
            #     if dis[i]==1:
            #         l[node][i+1]=1
            #         if l[parent][i+1]==level:
            #             edges.append([node,i+1])
            #         elif i+1!=parent:
            #             q.append(i+1)
        level+=1
    print("!")
    for i in range(len(edges)):
        edges[i].sort()
    edges = list(set(edges))
    for i in edges:
        print(*i)
    








t = 1
# t = ii()
for _ in range(t):
    solve()
