#include <bits/stdc++.h>
using namespace std;
struct _ {
  _() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
  }
} _;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
template <class T, class second>
void smax(T& a, const second& b) {
  if (b > a) a = b;
}
template <class T, class second>
void smin(T& a, const second& b) {
  if (b < a) a = b;
}
template <class T, class second>
T pop_begin(second& a) {
  auto it = a.begin();
  T ret = *it;
  a.erase(it);
  return ret;
}
void gotodie() {
  cout << "-1" << endl;
  exit(0);
}
struct MinCostMaxFlow {
  int n, qs;
  vector<vector<long long>> cap, cost, fnet;
  vector<vector<int>> adj;
  vector<long long> d, pi;
  vector<int> deg, par, q, inq;
  MinCostMaxFlow(int n)
      : n(n),
        qs(0),
        deg(n + 1),
        par(n + 1),
        d(n + 1),
        q(n + 1),
        inq(n + 1),
        pi(n + 1),
        cap(n + 1, vector<long long>(n + 1)),
        cost(cap),
        fnet(cap),
        adj(n + 1, vector<int>(n + 1)) {}
  void AddEdge(int from, int to, long long cap_, long long cost_) {
    cap[from][to] = cap_;
    cost[from][to] = cost_;
  }
  bool dijkstra(int s, int t) {
    fill(d.begin(), d.end(), 0x3f3f3f3f3f3f3f3fLL);
    fill(par.begin(), par.end(), -1);
    fill(inq.begin(), inq.end(), -1);
    d[s] = qs = 0;
    inq[q[qs++] = s] = 0;
    par[s] = n;
    while (qs) {
      int u = q[0];
      inq[u] = -1;
      q[0] = q[--qs];
      if (qs) inq[q[0]] = 0;
      for (int i = 0, j = 2 * i + 1, t; j < qs; i = j, j = 2 * i + 1) {
        if (j + 1 < qs && d[q[j + 1]] < d[q[j]]) j++;
        if (d[q[j]] >= d[q[i]]) break;
        {
          t = q[i];
          q[i] = q[j];
          q[j] = t;
          t = inq[q[i]];
          inq[q[i]] = inq[q[j]];
          inq[q[j]] = t;
        };
      }
      for (int k = 0, v = adj[u][k]; k < deg[u]; v = adj[u][++k]) {
        if (fnet[v][u] && d[v] > (d[u] + pi[u] - pi[v]) - cost[v][u])
          d[v] = (d[u] + pi[u] - pi[v]) - cost[v][par[v] = u];
        if (fnet[u][v] < cap[u][v] &&
            d[v] > (d[u] + pi[u] - pi[v]) + cost[u][v])
          d[v] = (d[u] + pi[u] - pi[v]) + cost[par[v] = u][v];
        if (par[v] == u) {
          if (inq[v] < 0) {
            inq[q[qs] = v] = qs;
            qs++;
          }
          for (int i = inq[v], j = (i - 1) / 2, t; d[q[i]] < d[q[j]];
               i = j, j = (i - 1) / 2) {
            t = q[i];
            q[i] = q[j];
            q[j] = t;
            t = inq[q[i]];
            inq[q[i]] = inq[q[j]];
            inq[q[j]] = t;
          };
        }
      }
    }
    for (int i = 0; i < n; i++)
      if (pi[i] < (LLONG_MAX / 2)) pi[i] += d[i];
    return par[t] >= 0;
  }
  pair<long long, long long> mcmf4(int s, int t) {
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (cap[i][j] || cap[j][i]) adj[i][deg[i]++] = j;
    long long flow = 0;
    long long fcost = 0;
    while (dijkstra(s, t)) {
      long long bot = LLONG_MAX;
      for (int v = t, u = par[v]; v != s; u = par[v = u])
        bot = min(bot, fnet[v][u] ? fnet[v][u] : (cap[u][v] - fnet[u][v]));
      for (int v = t, u = par[v]; v != s; u = par[v = u])
        if (fnet[v][u]) {
          fnet[v][u] -= bot;
          fcost -= bot * cost[v][u];
        } else {
          fnet[u][v] += bot;
          fcost += bot * cost[u][v];
        }
      flow += bot;
    }
    return make_pair(flow, fcost);
  }
};
bool take(vi& give, vi& from) {
  if (from.empty()) return false;
  give.push_back(from.back());
  from.pop_back();
  return true;
}
void sett(int cyclen, int dist, vector<vi>& lcyc, vi& ans, vi& take) {
  assert((int)(take).size());
  int nod = take.back();
  take.pop_back();
  if (lcyc[cyclen][dist - 1] == -1) gotodie();
  ans[nod] = lcyc[cyclen][dist - 1];
  lcyc[cyclen][dist] = nod;
}
string tmp;
signed main() {
  int N;
  cin >> N;
  vector<vector<vi>> k2(N + 1, vector<vi>(N + 1));
  vector<vi> kcyc(N + 1);
  vector<vi> kpre(N + 1);
  vi nk;
  bool seencyc = false;
  for (int i = 0; i < (N); ++i) {
    string pres, cycs;
    cin >> pres >> cycs;
    int pre, cyc;
    if (pres == "?")
      pre = -1;
    else
      pre = atoi(pres.c_str());
    if (cycs == "?")
      cyc = -1;
    else
      cyc = atoi(cycs.c_str());
    if (pre >= 0 && cyc >= 0) {
      k2[cyc][pre].push_back(i);
      seencyc = true;
    } else if (pre >= 0)
      kpre[pre].push_back(i);
    else if (cyc >= 0) {
      kcyc[cyc].push_back(i);
      seencyc = true;
    } else
      nk.push_back(i);
  }
  if (!seencyc) {
    if (!kpre[0].empty()) {
      take(kcyc[1], kpre[0]);
    } else if (!nk.empty()) {
      take(kcyc[1], nk);
    } else
      gotodie();
  }
  vi ans(N, -1);
  vector<vi> lcyc(N + 1, vi(N + 2, -1));
  vector<int> cycval(N + 1, 1);
  for (int i = 1; i < (N + 1); ++i) {
    for (int j = 1; j < (N); ++j)
      if (!k2[i][j].empty()) cycval[j]++;
    cycval[i] += (int)(kcyc[i]).size();
  }
  MinCostMaxFlow G(0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + 2 * N + 1);
  for (int cyc = 1; cyc < (N + 1); ++cyc)
    G.AddEdge(0, 0 + 1 + 1 + 2 * N + 1 + cyc, (int)(kcyc[cyc]).size(),
              301 * cycval[cyc]);
  for (int pre = 0; pre < (N); ++pre)
    G.AddEdge(0, 0 + 1 + 1 + pre, (int)(kpre[pre]).size(), 1);
  G.AddEdge(0, 0 + 1 + 1 + 2 * N + 1 + 2 * N + 1, (int)(nk).size(),
            301 * 301 * 301);
  map<pair<int, int>, int> nodes;
  for (int cyc = 1; cyc < (N + 1); ++cyc) {
    int cycneed = ((int)(k2[cyc][0]).size() + cyc - 1) / cyc;
    if ((int)(kcyc[cyc]).size()) smax(cycneed, 1);
    for (auto& it : k2[cyc])
      if ((int)(it).size()) smax(cycneed, 1);
    if (!cycneed) continue;
    for (int i = 0; i < (cycneed * cyc - (int)(k2[cyc][0]).size()); ++i) {
      nodes[make_pair(cyc, 0)]++;
    }
  }
  for (int cyc = 1; cyc < (N + 1); ++cyc) {
    int mxhas = 0;
    for (int i = 1; i < (N); ++i)
      if (!k2[cyc][i].empty()) mxhas = i;
    for (int i = 1; i < (mxhas + 1); ++i)
      if (k2[cyc][i].empty()) {
        nodes[make_pair(cyc, i)]++;
      }
  }
  int flo = 0;
  int nod = 0;
  for (auto& it : nodes) {
    int cyc = it.first.first;
    int i = it.first.second;
    int cap = it.second;
    flo += cap;
    G.AddEdge(0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod, 0 + 1, cap, 0);
    G.AddEdge(0 + 1 + 1 + 2 * N + 1 + 2 * N + 1,
              0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod, cap, 0);
    G.AddEdge(0 + 1 + 1 + 2 * N + 1 + cyc,
              0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod, cap, 0);
    G.AddEdge(0 + 1 + 1 + i, 0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod, cap,
              0);
    ++nod;
  }
  pair<long long, long long> mx = G.mcmf4(0, 0 + 1);
  if (mx.first != flo) gotodie();
  nod = 0;
  for (auto& it : nodes) {
    int cyc = it.first.first;
    int dist = it.first.second;
    for (int i = 0; i < (it.second); ++i) {
      if (G.fnet[0 + 1 + 1 + 2 * N + 1 + 2 * N + 1]
                [0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod]-- > 0)
        take(k2[cyc][dist], nk);
      else if (G.fnet[0 + 1 + 1 + 2 * N + 1 + cyc]
                     [0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod]-- > 0)
        take(k2[cyc][dist], kcyc[cyc]);
      else if (G.fnet[0 + 1 + 1 + dist]
                     [0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod]-- > 0)
        take(k2[cyc][dist], kpre[dist]);
      else {
        cout << 0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod << endl;
        assert(G.fnet[0 + 1 + 1 + 2 * N + 1 + 2 * N + 1 + 1 + nod][0 + 1]);
        assert(false);
      }
    }
    ++nod;
  }
  int bestcyc = -1;
  int bestval = -1;
  for (int i = 1; i < (N + 1); ++i) {
    if (k2[i][0].empty()) continue;
    int togo = (int)(kcyc[i]).size() + (int)(nk).size();
    for (int j = 1;; ++j) {
      if ((int)(kpre[j]).size() || (int)(k2[i][j]).size())
        continue;
      else if (togo)
        --togo;
      else {
        if (j > bestval) {
          bestval = j;
          bestcyc = i;
        }
        break;
      }
    }
  }
  assert(bestcyc != -1);
  while (!nk.empty()) take(kcyc[bestcyc], nk);
  for (int i = 1; i < (bestval); ++i) {
    while (!kpre[i].empty()) take(k2[bestcyc][i], kpre[i]);
  }
  while (!kpre[0].empty()) take(k2[1][0], kpre[0]);
  for (int i = 1; i < (N + 1); ++i) {
    assert((int)(k2[i][0]).size() % i == 0);
    while ((int)(k2[i][0]).size()) {
      int f = k2[i][0].back();
      for (int j = 0; j < (i - 1); ++j) {
        int nnod = k2[i][0].back();
        k2[i][0].pop_back();
        ans[nnod] = k2[i][0].back();
      }
      lcyc[i][0] = f;
      ans[k2[i][0].back()] = f;
      k2[i][0].pop_back();
    }
    for (int j = 1; j < bestval; j++) {
      if (k2[i][j].empty() && (int)(kcyc[i]).size()) {
        sett(i, j, lcyc, ans, kcyc[i]);
      }
      while ((int)(k2[i][j]).size()) sett(i, j, lcyc, ans, k2[i][j]);
    }
  }
  for (auto& it : kpre)
    if (!it.empty()) gotodie();
  for (int i = 0; i < (N); ++i) cout << ans[i] + 1 << " ";
  cout << endl;
  return 0;
}
