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.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.Objects;
import java.util.Set;

/**
 * @author ethan55
 */
public class Solution {

  public static void main(String[] args) {
    TestRunner.run();
  }

  public static class InputReader {

    private final InputStream inputStream;
    private final byte[] inputBuffer = new byte[1024];
    private int bytesRead = 0;
    private int inputBufferIndex = 0;

    public InputReader(InputStream inputStream) {
      this.inputStream = inputStream;
    }

    private int readByte() {
      if (bytesRead == -1) {
        throw new InputMismatchException();
      }
      if (inputBufferIndex >= bytesRead) {
        inputBufferIndex = 0;
        try {
          bytesRead = inputStream.read(inputBuffer);
        } catch (IOException e) {
          throw new InputMismatchException();
        }
        if (bytesRead <= 0) {
          return -1;
        }
      }
      return inputBuffer[inputBufferIndex++];
    }

    public int nextInt() {
      return (int) nextLong();
    }

    public long nextLong() {
      long num = 0;
      int b;
      boolean minus = false;
      do {
        b = readByte();
      } while (b != -1 && !((b >= '0' && b <= '9') || b == '-'));
      if (b == '-') {
        minus = true;
        b = readByte();
      }

      while (true) {
        if (b >= '0' && b <= '9') {
          num = num * 10 + (b - '0');
        } else {
          return minus ? -num : num;
        }
        b = readByte();
      }
    }

    public int[] nextIntArray(int n) {
      int[] a = new int[n];
      for (int i = 0; i < n; i++) {
        a[i] = nextInt();
      }
      return a;
    }

  }

  public static class OutputWriter {

    private static final int BUFFER_SIZE = 1 << 13;
    private final byte[] outputBuffer = new byte[BUFFER_SIZE];
    private final OutputStream outputStream;
    private int outputBufferIndex = 0;

    public OutputWriter(OutputStream os) {
      this.outputStream = os;
    }

    public OutputWriter println(String s) {
      return writeln(s);
    }

    public void flush() {
      innerFlush();
      try {
        outputStream.flush();
      } catch (IOException e) {
        throw new IllegalStateException("Failed to flush");
      }
    }

    private OutputWriter write(byte b) {
      outputBuffer[outputBufferIndex++] = b;
      if (outputBufferIndex == BUFFER_SIZE) {
        innerFlush();
      }
      return this;
    }

    private OutputWriter write(String s) {
      s.chars()
          .forEach(
              c -> {
                outputBuffer[outputBufferIndex++] = (byte) c;
                if (outputBufferIndex == BUFFER_SIZE) {
                  innerFlush();
                }
              });
      return this;
    }

    private OutputWriter writeln() {
      return write((byte) '\n');
    }

    private OutputWriter writeln(String s) {
      return write(s).writeln();
    }

    private void innerFlush() {
      try {
        outputStream.write(outputBuffer, 0, outputBufferIndex);
        outputBufferIndex = 0;
      } catch (IOException e) {
        throw new IllegalStateException("Failed to inner flush");
      }
    }
  }

  public static class TestCase {

    static final boolean MULTIPLE = false;

    static class Edge {

      int a;
      int b;

      public Edge(int a, int b) {
        this.a = a;
        this.b = b;
      }

      @Override
      public boolean equals(Object o) {
        if (this == o) {
          return true;
        }
        if (o == null || getClass() != o.getClass()) {
          return false;
        }
        Edge edge = (Edge) o;
        return a == edge.a && b == edge.b;
      }

      @Override
      public int hashCode() {
        return Objects.hash(a, b);
      }

    }

    public void solve(InputReader in, OutputWriter out) {
      int n = in.nextInt();
      Set<Integer> toGuess = new HashSet<>();
      for (int i = 1; i <= n; i++) {
        toGuess.add(i);
      }
      Set<Edge> result = new HashSet<>();
      while (!toGuess.isEmpty()) {
        int guess = toGuess.iterator().next();

        out.println("? " + guess);
        out.flush();

        int[] dist = in.nextIntArray(n);
        boolean found = true;
        while (found) {
          found = false;
          int oneAwayCount = 0;
          int oneAway = 0;
          for (int i = 0; i < dist.length; i++) {
            if (dist[i] == 1) {
              oneAwayCount++;
              oneAway = i + 1;
              int from = i + 1;
              int to = guess;
              if (from > to) {
                int tmp = from;
                from = to;
                to = tmp;
              }
              result.add(new Edge(from, to));
              toGuess.remove(i + 1);
            }
          }
          if (oneAwayCount == 1) {
            found = true;
            for (int i = 0; i < dist.length; i++) {
              if (dist[i] == 2) {

                int from = oneAway;
                int to = i + 1;
                if (from > to) {
                  int tmp = from;
                  from = to;
                  to = tmp;
                }
                result.add(new Edge(from, to));
                toGuess.remove(i + 1);
              }
              dist[i]--;

            }
          }
          toGuess.remove(guess);
          guess = oneAway;
        }

      }

      out.println("!");
      out.flush();
      for (Edge e : result) {
        out.println(e.a + " " + e.b);
      }
    }
  }

  public static class TestRunner {

    public static void run() {
      InputReader in = new InputReader(System.in);
      OutputWriter out = new OutputWriter(System.out);
      int testCases = TestCase.MULTIPLE ? in.nextInt() : 1;
      for (int i = 1; i <= testCases; i++) {
        new TestCase().solve(in, out);
      }
      out.flush();
    }

  }
}