#include <bits/stdc++.h>
using namespace std;
template <class T>
bool chkmin(T& a, T b) {
  return a > b ? a = b, 1 : 0;
}
template <class T>
bool chkmax(T& a, T b) {
  return a < b ? a = b, 1 : 0;
}
const int maxN = 405;
struct Edge {
  int v, next;
} G[maxN * maxN];
struct Data {
  int pre, rou;
  Data() {}
  Data(int pre, int rou) : pre(pre), rou(rou) {}
};
Data inp[maxN], rig[maxN];
int totinrou[maxN], mxdeep[maxN];
int mxunknowndeep;
int N;
int totrig;
int st[maxN], e;
int mtx[maxN], mty[maxN];
bool used[maxN];
void addedge(int u, int v) {
  G[++e] = (Edge){v, st[u]};
  st[u] = e;
}
void gi(int& a) {
  char c = getchar();
  a = 0;
  for (; isdigit(c) == 0; c = getchar()) {
    if (c == '?') {
      a = -1;
      return;
    }
  }
  for (; isdigit(c) != 0; c = getchar()) a = a * 10 + c - '0';
}
bool dfs(int u) {
  for (int e = st[u]; e; e = G[e].next) {
    int v = G[e].v;
    if (used[v]) continue;
    used[v] = 1;
    if (mty[v] == 0 || dfs(mty[v])) {
      mtx[mty[v] = u] = v;
      return 1;
    }
  }
  return 0;
}
bool work(int wh, int mxunknowndeep) {
  totrig = 0;
  bool appear = 0;
  for (int i = (1), _ = (N); i <= _; ++i)
    if (~totinrou[i]) {
      int totrou = totinrou[i] == 0 ? 1 : (totinrou[i] - 1) / i + 1;
      int mxpre = mxdeep[i];
      if (wh == i) {
        chkmax(mxpre, mxunknowndeep);
        appear = 1;
      }
      for (int j = (1), _ = (totrou * i); j <= _; ++j)
        rig[++totrig] = Data(0, i);
      if (totrig > N) return 0;
      for (int j = (1), _ = (mxpre); j <= _; ++j) rig[++totrig] = Data(j, i);
      if (totrig > N) return 0;
    }
  if (appear == 0) {
    for (int j = (1), _ = (wh); j <= _; ++j) rig[++totrig] = Data(0, wh);
    if (totrig > N) return 0;
    for (int j = (1), _ = (mxunknowndeep); j <= _; ++j)
      rig[++totrig] = Data(j, wh);
    if (totrig > N) return 0;
  }
  int cntmatch = 0;
  memset(mtx, 0, sizeof(*mtx) * (N + 1));
  memset(mty, 0, sizeof(*mty) * (totrig + 1));
  memset(st, 0, sizeof(*st) * (N + 1));
  e = 0;
  for (int i = (1), _ = (N); i <= _; ++i)
    if (inp[i].pre == 0 && inp[i].rou != -1) {
      for (int j = (1), _ = (totrig); j <= _; ++j)
        if (inp[i].pre == rig[j].pre && inp[i].rou == rig[j].rou) addedge(i, j);
    }
  for (int i = (1), _ = (N); i <= _; ++i)
    if (mtx[i] == 0) {
      memset(used, 0, sizeof(*used) * (totrig + 1));
      cntmatch += dfs(i);
    }
  for (int i = (1), _ = (N); i <= _; ++i)
    if (!(inp[i].pre == 0 && inp[i].rou != -1)) {
      for (int j = (1), _ = (totrig); j <= _; ++j)
        if ((!~inp[i].pre || (inp[i].pre == rig[j].pre)) &&
            (!~inp[i].rou || (inp[i].rou == rig[j].rou)))
          addedge(i, j);
    }
  for (int i = (1), _ = (N); i <= _; ++i)
    if (mtx[i] == 0) {
      memset(used, 0, sizeof(*used) * (totrig + 1));
      cntmatch += dfs(i);
    }
  return cntmatch == totrig;
}
void getans(int hangin) {
  static int stf[maxN][maxN];
  static Data sur[maxN];
  static int ans[maxN];
  for (int i = (1), _ = (N); i <= _; ++i)
    if (mtx[i]) {
      sur[i] = rig[mtx[i]];
    } else {
      sur[i] = inp[i];
    }
  for (int i = (1), _ = (N); i <= _; ++i)
    if (~sur[i].pre && ~sur[i].rou) {
      stf[sur[i].pre][sur[i].rou] = i;
    }
  for (int i = (1), _ = (N); i <= _; ++i)
    if ((sur[i].pre == -1 || sur[i].pre == 0) && sur[i].rou == -1) {
      ans[i] = i;
    }
  for (int len = (1), _ = (N); len <= _; ++len) {
    static int stk[maxN];
    int tp = 0;
    for (int i = (1), _ = (N); i <= _; ++i)
      if (len == sur[i].rou && sur[i].pre == 0) {
        stk[++tp] = i;
        if (tp == len) {
          for (int j = (1), _ = (tp - 1); j <= _; ++j) ans[stk[j]] = stk[j + 1];
          ans[stk[tp]] = stk[1];
          tp = 0;
        }
      }
    assert(tp == 0);
  }
  for (int i = (1), _ = (N); i <= _; ++i) {
    int pre = sur[i].pre, rou = sur[i].rou;
    if ((pre == 0 && rou != -1) || (pre == 0 && rou == -1) ||
        (pre == -1 && rou == -1))
      continue;
    if (~pre && ~rou) {
      ans[i] = stf[pre - 1][rou];
    } else if (pre == -1 && ~rou) {
      ans[i] = stf[0][rou];
    } else if (~pre && rou == -1) {
      ans[i] = stf[pre - 1][hangin];
    }
  }
  for (int i = (1), _ = (N); i <= _; ++i)
    if (ans[i] == 0) {
      cout << "sur[i].pre"
           << "=" << sur[i].pre << "; ",
          cout << "sur[i].rou"
               << "=" << sur[i].rou << "; ",
          puts("");
    }
  for (int i = (1), _ = (N); i <= _; ++i) printf("%d ", ans[i]);
  puts("");
}
int main() {
  int hangin = 0;
  gi(N);
  memset(totinrou, -1, sizeof(totinrou));
  for (int i = (1), _ = (N); i <= _; ++i) {
    int pre, rou;
    gi(pre), gi(rou);
    inp[i] = Data(pre, rou);
    if (pre == -1 && rou == -1) continue;
    if (~rou) {
      if (totinrou[rou] == -1) totinrou[rou] = 0;
      if (pre == 0) totinrou[rou]++;
    }
    if (rou == -1 && ~pre) {
      chkmax(mxunknowndeep, pre);
    }
    if (~rou && ~pre) {
      chkmax(mxdeep[rou], pre);
    }
  }
  for (int i = (1), _ = (N); i <= _; ++i) {
    if (work(i, mxunknowndeep)) {
      hangin = i;
      break;
    }
  }
  if (hangin)
    getans(hangin);
  else
    puts("-1");
  return 0;
}
