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 os, sys
from io import BytesIO, IOBase
from types import GeneratorType
from bisect import *
from collections import defaultdict, deque, Counter
import math, string
from heapq import *
from operator import add
from itertools import accumulate

BUFSIZE = 8192
sys.setrecursionlimit(10 ** 5)


class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        import os

        self.os = os
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = "x" in file.mode or "r" not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = self.os.read(self._fd, max(self.os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = self.os.read(self._fd, max(self.os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b"\n") + (not b)
            ptr = self.buffer.tell()
            self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr)
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            self.os.write(self._fd, self.buffer.getvalue())
            self.buffer.truncate(0), self.buffer.seek(0)


class IOWrapper(IOBase):
    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode("ascii"))
        self.read = lambda: self.buffer.read().decode("ascii")
        self.readline = lambda: self.buffer.readline().decode("ascii")


sys.stdin, sys.stdout = IOWrapper(sys.stdin), IOWrapper(sys.stdout)
input = lambda: sys.stdin.readline().rstrip("\r\n")


inf = float("inf")
en = lambda x: list(enumerate(x))
ceil_ = lambda a, b: (a + b - 1) // b


ii = lambda: int(input())
r = lambda: map(int, input().split())
rr = lambda: list(r())


# --------------------------


n = ii()
sys.stdout.flush()
mat = [[0] * (n + 1) for _ in " " * (n + 1)]
arr = defaultdict(list)
ok = []
last = 0


def solve(x):
    ans = defaultdict(lambda: 0)
    xx = []
    for i, j in x:
        if ans[(j, i)] == 0 and ans[(i, j)] == 0:
            xx += ((i, j),)
            ans[(j, i)] = 1
            ans[(i, j)] = 1

    print("!")
    for i, j in xx:
        print(i, j)


# --------------------------


def dfs(i, par):
    global tree, arr, ok, n, last

    print("?", i, flush=True)
    arr[i] = rr()

    # --------------------------
    temp = defaultdict(list)
    for x, y in enumerate(arr[i], 1):
        temp[y] += (x,)

    z = 1
    while 1:
        if temp[z - 1] and len(temp[z]) == 1:
            ok += ((temp[z - 1][0], temp[z][0]),)
            ok += ((temp[z][0], temp[z - 1][0]),)
        else:
            break
        z += 1

    # --------------------------

    if not temp[z]:
        solve(ok)
        exit()

    # print("z:", z)

    for x, j in enumerate(arr[i], 1):
        if j == z:
            ok += ((temp[z - 1][0], x),)
            ok += ((x, temp[z - 1][0]),)
            if len(ok) >= (n - 1) * 2:
                solve(ok)
                exit()

    for x, j in enumerate(arr[i], 1):
        if j == z and x != par:
            dfs(x, i)


dfs(1, -1)
