#include <bits/stdc++.h>
using namespace std;
vector<string> split(const string& s, char c) {
  vector<string> v;
  stringstream ss(s);
  string x;
  while (getline(ss, x, c)) v.emplace_back(x);
  return move(v);
}
void err(vector<string>::iterator it) {}
template <typename T, typename... Args>
void err(vector<string>::iterator it, T a, Args... args) {
  cerr << a << " ";
  err(++it, args...);
}
const int M = 310, mod = 1000000007;
int cnt[M][M], ache[M], ans[M];
vector<int> eie[M][M];
vector<pair<int, int> > needed, reserve;
pair<int, int> g[M];
int maxx[M], node[M];
int find_max(int c) {
  for (int i = M - 1; i >= 0; i--)
    if (cnt[c][i]) return i;
  return -1;
}
int visited[M], matched_with[M], left_match[M];
bool find_new_match(int u) {
  for (int v = 0; v < reserve.size(); v++) {
    if (visited[v] == true) continue;
    if (reserve[v] == make_pair(-1, -1) ||
        reserve[v].first == needed[u].first ||
        reserve[v].second == needed[u].second) {
      if (matched_with[v] == -1) {
        matched_with[v] = u;
        left_match[u] = v;
        return true;
      } else if (matched_with[v] != u) {
        visited[v] = true;
        if (find_new_match(matched_with[v])) {
          matched_with[v] = u;
          left_match[u] = v;
          return true;
        }
      }
    }
  }
  return false;
}
int _max_match() {
  int i, _match = 0;
  memset((matched_with), (-1), sizeof(matched_with));
  memset((left_match), (-1), sizeof(left_match));
  _match = 0;
  for (i = 0; i < needed.size(); i++) {
    if (left_match[i] == -1) {
      memset((visited), (false), sizeof(visited));
      if (find_new_match(i)) {
        _match++;
      }
    }
  }
  return _match;
}
int pop_last_elem(vector<int>& p) {
  int k = p[p.size() - 1];
  p.pop_back();
  return k;
}
int main() {
  ios_base::sync_with_stdio(false);
  int i, j, k, n, maxlen = 0, gotcha = false;
  char a[100], b[100];
  memset((cnt), (0), sizeof(cnt));
  memset((ache), (0), sizeof(ache));
  memset((ans), (-1), sizeof(ans));
  memset((maxx), (0), sizeof(maxx));
  cin >> n;
  for (i = 1; i <= n; i++) {
    cin >> a >> b;
    g[i].first = a[0] == '?' ? -1 : atoi(a);
    g[i].second = b[0] == '?' ? -1 : atoi(b);
    if (g[i].first != -1 && g[i].second != -1) {
      cnt[g[i].second][g[i].first]++;
      eie[g[i].second][g[i].first].push_back(i);
      maxx[g[i].second] = max(maxx[g[i].second], g[i].first);
    }
    if (g[i].second != -1) ache[g[i].second] = true, gotcha = true;
    if (g[i].second == -1 && g[i].first != -1) maxlen = max(maxlen, g[i].first);
  }
  for (i = 1; i <= n; i++) {
    if (cnt[i][0]) {
      while (cnt[i][0] > i) {
        vector<int> t;
        for (j = 0; j < i; j++) {
          t.push_back(pop_last_elem(eie[i][0]));
          cnt[i][0]--;
        }
        for (j = 0; j < t.size() - 1; j++) ans[t[j]] = t[j + 1];
        ans[t[j]] = t[0];
      }
      cnt[i][0] %= i;
      if (cnt[i][0] == 0) cnt[i][0] = i;
    }
  }
  for (i = 1; i <= n; i++)
    if (g[i].second == -1 || g[i].first == -1)
      node[reserve.size()] = i, reserve.push_back(g[i]);
  if (!gotcha) ache[1] = true;
  int II = -1;
  for (int uu = 1; uu <= n; uu++) {
    if (ache[uu]) {
      needed.clear();
      for (i = 1; i <= n; i++) {
        if (ache[i]) {
          int loop = i == uu ? max(maxlen, maxx[i]) : maxx[i];
          for (j = cnt[i][0] + 1; j <= i; j++)
            needed.push_back(make_pair(0, i));
          for (j = 1; j <= loop; j++)
            if (cnt[i][j] == 0) needed.push_back(make_pair(j, i));
        }
      }
      k = _max_match();
      if (k == needed.size()) {
        II = uu;
        break;
      }
    }
  }
  if (II == -1) {
    printf("%s\n", "-1");
    return 0;
  };
  for (i = 0; i < reserve.size(); i++) {
    if (matched_with[i] == -1) continue;
    pair<int, int> t = needed[matched_with[i]];
    cnt[t.second][t.first]++;
    eie[t.second][t.first].push_back(node[i]);
  }
  int imax = 0, um = 0;
  for (i = 1; i <= n; i++)
    if (find_max(i) > imax) imax = find_max(i), um = i;
  for (i = 0; i < reserve.size(); i++) {
    if (matched_with[i] == -1) {
      pair<int, int> t = reserve[i];
      if (t.first == 0) t.second = 1;
      if (t.second == -1 && t.first == -1) t = make_pair(0, 1);
      if (t.second == -1) t.second = um;
      if (t.first == -1) t.first = 1;
      cnt[t.second][t.first]++;
      eie[t.second][t.first].push_back(node[i]);
    }
  }
  for (i = 1; i <= n; i++) {
    if (cnt[i][0]) {
      if (i == 1) {
        for (j = 0; j < eie[i][0].size(); j++) ans[eie[i][0][j]] = eie[i][0][j];
      } else {
        for (j = 0; j < eie[i][0].size() - 1; j++)
          ans[eie[i][0][j]] = eie[i][0][j + 1];
        ans[eie[i][0][j]] = eie[i][0][0];
      }
      for (j = 1; j <= find_max(i); j++) {
        for (k = 0; k < eie[i][j].size(); k++) {
          ans[eie[i][j][k]] = eie[i][j - 1][0];
        }
      }
    }
  }
  for (i = 1; i <= n; i++) printf("%d ", ans[i]);
  printf("\n");
  return 0;
}
