#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
const int MAXE = 1000005;
const int INF = 0x3f3f3f3f;
struct Edge {
  int v, c, n;
  Edge() {}
  Edge(int v, int c, int n) : v(v), c(c), n(n) {}
};
int H[MAXN], cntE;
Edge E[MAXE];
int d[MAXN], gap[MAXN], cur[MAXN], pre[MAXN];
int s, t, nv, flow;
int n;
int disc[MAXN], sizc[MAXN];
int tree[MAXN][MAXN];
vector<int> cir[MAXN];
int nolim[MAXN];
int used[MAXN];
int siz[MAXN];
int nxt[MAXN];
int has[MAXN];
pair<int, int> pos[MAXN];
void addedge(int u, int v, int c) {
  E[cntE] = Edge(v, c, H[u]);
  H[u] = cntE++;
  E[cntE] = Edge(u, 0, H[v]);
  H[v] = cntE++;
}
void rev_bfs() {
  memset(d, -1, sizeof d);
  memset(gap, 0, sizeof gap);
  queue<int> q;
  for (q.push(t), gap[d[t] = 0] = 1; !q.empty(); q.pop()) {
    for (int u = q.front(), i = H[u]; ~i; i = E[i].n) {
      int v = E[i].v;
      if (d[v] == -1) {
        gap[d[v] = d[u] + 1]++;
        q.push(v);
      }
    }
  }
}
int isap() {
  memcpy(cur, H, sizeof cur);
  flow = 0;
  rev_bfs();
  int u = pre[s] = s, i;
  while (d[s] < nv) {
    if (u == t) {
      int f = INF;
      for (i = s; i != t; i = E[cur[i]].v) {
        if (f > E[cur[i]].c) {
          f = E[cur[i]].c;
          u = i;
        }
      }
      flow += f;
      for (i = s; i != t; i = E[cur[i]].v) {
        E[cur[i]].c -= f;
        E[cur[i] ^ 1].c += f;
      }
    }
    for (i = cur[u]; ~i; i = E[i].n) {
      int v = E[i].v;
      if (E[i].c && d[u] == d[v] + 1) break;
    }
    if (~i) {
      cur[u] = i;
      pre[E[i].v] = u;
      u = E[i].v;
    } else {
      if (0 == --gap[d[u]]) break;
      int minv = nv;
      for (int i = H[u]; ~i; i = E[i].n) {
        int v = E[i].v;
        if (E[i].c && minv > d[v]) {
          minv = d[v];
          cur[u] = i;
        }
      }
      d[u] = minv + 1;
      gap[d[u]]++;
      u = pre[u];
    }
  }
  return flow;
}
int get() {
  char s[5];
  scanf("%s", s);
  if (s[0] == '?') return -1;
  int x;
  sscanf(s, "%d", &x);
  return x;
}
void print() {
  memset(used, 0, sizeof used);
  for (int i = H[s]; ~i; i = E[i].n)
    if (E[i].c == 0) {
      int u = E[i].v;
      for (int j = H[u]; ~j; j = E[j].n)
        if (E[j].c == 0) {
          int v = E[j].v;
          if (v <= n + n)
            cir[v - n].push_back(u);
          else {
            int x = pos[v].first, y = pos[v].second;
            tree[x][y] = u;
          }
        }
    }
  for (int i = 1; i <= n; ++i)
    if (has[i]) {
      tree[i][0] = cir[i][0];
      for (int j = 1; j <= siz[i]; ++j) {
        used[tree[i][j]] = 1;
        nxt[tree[i][j]] = tree[i][j - 1];
      }
      for (int j = 0; j < cir[i].size(); ++j) {
        used[cir[i][j]] = 1;
      }
      int now = 0;
      for (int j = 0; j < cir[i].size(); ++j) {
        used[cir[i][j]] = 1;
        if (j == now)
          nxt[cir[i][j]] = cir[i][j + i - 1], now += i;
        else
          nxt[cir[i][j]] = cir[i][j - 1];
      }
    }
  for (int i = 1; i <= n; ++i)
    if (!used[i]) {
      if (disc[i] == -1) {
        if (sizc[i] == -1)
          nxt[i] = i;
        else
          nxt[i] = cir[sizc[i]][0];
      } else {
        if (sizc[i] == -1) {
          if (disc[i] == 0)
            nxt[i] = i;
          else {
            for (int j = 1; j <= n; ++j) {
              if (tree[j][disc[i] - 1]) {
                nxt[i] = tree[j][disc[i] - 1];
                break;
              }
            }
          }
        } else
          nxt[i] = tree[sizc[i]][disc[i] - 1];
      }
    }
  for (int i = 1; i <= n; ++i) {
    printf("%d%c", nxt[i], i < n ? ' ' : '\n');
  }
}
int cnt;
int check() {
  cntE = 0;
  memset(H, -1, sizeof H);
  s = 0;
  t = n + n + n + 1;
  nv = t + 1;
  int L = 0, R = 0;
  for (int i = 1; i <= n; ++i)
    if (!nolim[i]) {
      if (disc[i] == -1 || sizc[i] == -1) {
        addedge(s, i, 1);
        ++L;
      }
    }
  int tot = n + n;
  for (int i = 1; i <= n; ++i)
    if (has[i]) {
      if (cir[i].size() % i || !cir[i].size()) {
        addedge(n + i, t, i - cir[i].size() % i);
        R += i - cir[i].size() % i;
        if (R > L) return 0;
        for (int j = 1; j <= n; ++j) {
          if (disc[j] == -1 && sizc[j] == -1) {
            addedge(j, n + i, 1);
          } else if (disc[j] == -1 && sizc[j] == i) {
            addedge(j, n + i, 1);
          } else if (disc[j] == 0 && sizc[j] == -1) {
            addedge(j, n + i, 1);
          }
        }
      }
      for (siz[i] = n; siz[i] >= 1; --siz[i])
        if (tree[i][siz[i]]) break;
      for (int j = 1; j <= siz[i]; ++j)
        if (!tree[i][j]) {
          ++tot;
          ++R;
          if (R > L) return 0;
          pos[tot] = pair<int, int>(i, j);
          addedge(tot, t, 1);
          for (int k = 1; k <= n; ++k)
            if (!nolim[k]) {
              if (disc[k] == -1 && sizc[k] == -1) {
                addedge(k, tot, 1);
              } else if (disc[k] == -1 && sizc[k] == i) {
                addedge(k, tot, 1);
              } else if (disc[k] == j && sizc[k] == -1) {
                addedge(k, tot, 1);
              }
            }
        }
    }
  isap();
  if (flow < R) return 0;
  print();
  return 1;
}
void solve() {
  memset(tree, 0, sizeof tree);
  for (int i = 1; i <= n; ++i) {
    cir[i].clear();
    has[i] = 0;
    nolim[i] = 0;
  }
  int maxv = 0, nocir = 1;
  for (int i = 1; i <= n; ++i) {
    disc[i] = get();
    sizc[i] = get();
    if (sizc[i] >= 0) has[sizc[i]] = 1, nocir = 0;
    if (disc[i] >= 0 && sizc[i] >= 0) {
      maxv = max(maxv, disc[i]);
      if (disc[i] == 0)
        cir[sizc[i]].push_back(i);
      else
        tree[sizc[i]][disc[i]] = i;
    }
  }
  for (int i = 1; i <= n; ++i) {
    if (disc[i] > maxv && sizc[i] == -1) {
      nolim[i] = 1;
    }
  }
  cnt = 0;
  if (!nocir) {
    for (int i = 1; i <= n; ++i)
      if (has[i]) {
        for (int j = 1; j <= n; ++j)
          if (nolim[j]) {
            tree[i][disc[j]] = j;
          }
        if (check()) return;
        for (int j = 1; j <= n; ++j)
          if (nolim[j]) {
            tree[i][disc[j]] = 0;
          }
      }
  } else {
    has[1] = 1;
    for (int j = 1; j <= n; ++j)
      if (nolim[j]) {
        tree[1][disc[j]] = j;
      }
    if (check()) return;
  }
  printf("-1\n");
}
int main() {
  while (~scanf("%d", &n)) solve();
  return 0;
}
