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

////#pragma GCC optimize ("unroll-loops")
////#pragma GCC optimize ("Ofast")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ll   int
#define ld   long double
#define int  long long
#define pb push_back
#define F first
#define S second
#define ull unsigned long long
#define all(x) (x).begin(),(x).end()
#define pii pair <int, int>


using namespace std;
using namespace __gnu_pbds;
template < typename T >
using ordered_set = tree <T, null_type, less <T>, rb_tree_tag, tree_order_statistics_node_update>;
mt19937_64 gen(chrono::high_resolution_clock::now().time_since_epoch().count());
const int N = (5e5 + 10);
const int MOD = (1e9 + 7);
int pr[N];
int get(int  x){
if(pr[x] ==x) return x;
return (pr[x] = get(pr[x]));
}
void add(int x, int y){
x = get(x);
y = get(y);
if(x == y) return;
pr[x] = y;
}
main() {
//#ifdef LOCAL
//    freopen("input.txt","r",stdin);
//    freopen("output.txt","w",stdout);
//#endif // LOCAL
//    ios_base::sync_with_stdio(0);
//    cin.tie(0);
//    cout.tie(0);
    ll t = 1;
//    cin >> 1;
    while(t--) {
        ll n;
        cin >> n;
        vector < int > used(n, 0);
        vector < pii > ans;
        for(int i =0 ;i < n; i++){
            if(used[i] != 0) continue;
            cout << "? " << i + 1 << "\n";
            cout.flush();
            for(int j = 0;j < n; j++){
                ll x;
                cin >> x;
                if(x == 1){
                    used[j] = 1;
                    ans.pb({i + 1, j + 1});
                }
            }
        }
        cout << "!\n";
        for(auto to : ans)
            cout << to.F << " " << to.S <<"\n";
            cout.flush();

    }
}
