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

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

vector<int> query_distances(int node, int n)
{
	cout << "? " <<  node << endl;
	vector<int> distances(n + 1);
	for (int i = 1; i <= n; i++)
		cin >> distances[i];
	return distances;
}
vector<int> query_neighbors(int node, int n)
{
	auto distances = query_distances(node, n);
	vector<int> neighbors;
	for (int i = 1; i <= n; i++)
	{
		if (distances[i] == 1)
		{
			neighbors.push_back(i);
		}
	}
	return neighbors;
}

int main()
{
	int n; cin >> n;
	vector<int> color(n + 1);
	auto distances = query_distances(1, n);
	vector<int> nodes_color_0, nodes_color_1;
	for (int i = 2; i <= n; i++)
	{
		if (distances[i] % 2 == 1)
		{
			nodes_color_0.push_back(i);
		}
		else
		{
			nodes_color_1.push_back(i);
		}
	}
	vector<pair<int, int>> edges; edges.reserve(n - 1);
	if (nodes_color_1.size() <= nodes_color_0.size())
	{
		for (int i = 1; i <= n; i++)
		{
			if (distances[i] == 1)
			{
				edges.emplace_back(1, i);
			}
		}
	}

	vector<int>& nodes_to_query = nodes_color_0.size() < nodes_color_1.size() ? nodes_color_0 : nodes_color_1;
	for (int node: nodes_to_query)
	{
		auto neighbors = query_neighbors(node, n);
		for (int neighbor: neighbors)
		{
			edges.emplace_back(node, neighbor);
		}
	}
	cout << "!" << endl;
	for (auto edge: edges)
	{
		cout << edge.first << " " << edge.second << endl;
	}
	
	return 0;
}