// implement 30min #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; static const double EPS = 1e-9; static const double PI = acos(-1.0); #define REP(i, n) for (int i = 0; i < (int)(n); i++) #define FOR(i, s, n) for (int i = (s); i < (int)(n); i++) #define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++) #define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++) #define MEMSET(v, h) memset((v), h, sizeof(v)) typedef ll Weight; struct Edge { int index; int src; int dest; Weight capacity; Weight cost; Edge(int index, int src, int dest, Weight capacity, Weight cost) : index(index), src(src), dest(dest), capacity(capacity), cost(cost) {;} bool operator<(const Edge &rhs) const { if (cost != rhs.cost) { return cost > rhs.cost; } if (src != rhs.src) { return src < rhs.src; } return dest < rhs.dest; } }; typedef vector Edges; typedef vector Graph; typedef vector Array; typedef vector Matrix; void printMatrix(const Matrix &matrix) { for (int y = 0; y < (int)matrix.size(); y++) { for (int x = 0; x < (int)matrix[y].size(); x++) { printf("%lld ", matrix[y][x]); } puts(""); } } // index^1 is reverse edge pair MinCostFlow(const Graph &g, int e, int s, int t) { const int n = g.size(); Array capacity(e, 0); for (int from = 0; from < n; from++) { for (Edges::const_iterator it = g[from].begin(); it != g[from].end(); it++) { capacity[it->index] += it->capacity; } } pair ret = make_pair(0, 0); vector > parent(n); vector prev_dist(n, 0); vector now_dist(n); // calc potential for (int iter = 0; iter < n; iter++) { bool end = true; for (int from = 0; from < n; from++) { for (int i = 0; i < (int)g[from].size(); i++) { if (capacity[g[from][i].index] <= 0) { continue; } int to = g[from][i].dest; Weight ncost = prev_dist[from] + g[from][i].cost; if (ncost < prev_dist[to]) { end = false; prev_dist[to] = ncost; } } } if (end) { break; } if (iter == n - 1) { assert(false); // exist negative cycle } } while (true) { fill(parent.begin(), parent.end(), make_pair(-1, -1)); fill(now_dist.begin(), now_dist.end(), 2000000000LL); priority_queue que; que.push(Edge(e, s, s, 0, 0)); now_dist[s] = 0; while (!que.empty()) { Edge node = que.top(); que.pop(); if (parent[node.dest].first != -1) { continue; } parent[node.dest] = make_pair(node.src, node.index); int from = node.dest; for (int i = 0; i < (int)g[from].size(); i++) { int to = g[from][i].dest; int index = g[from][i].index; Weight ncost = node.cost + g[from][i].cost + (prev_dist[from] - prev_dist[to]); if (capacity[index] <= 0) { continue; } if (ncost >= now_dist[to]) { continue; } now_dist[to] = ncost; que.push(Edge(i, from, to, 0, ncost)); } } if (parent[t].first == -1) { break; } pair index = parent[t]; Weight flow = 2000000000LL; while (index.second != e) { flow = min(flow, capacity[g[index.first][index.second].index]); index = parent[index.first]; } ret.first += flow; index = parent[t]; while (index.second != e) { Edge edge = g[index.first][index.second]; ret.second += flow * edge.cost; capacity[edge.index] -= flow; capacity[edge.index^1] += flow; index = parent[index.first]; } for (int i = 0; i < n; i++) { prev_dist[i] += now_dist[i]; } } return ret; } void AddEdge(Graph &g, int &e, int from, int to, Weight capacity, Weight cost) { g[from].push_back(Edge(e++, from, to, capacity, cost)); g[to].push_back(Edge(e++, to, from, 0, -cost)); } static const Weight INF = 1LL << 58; vector SPFA(const Graph &g, int s) { const int n = g.size(); vector dist = vector(n, 1LL << 58); dist[s] = 0; vector updated(n, 0); vector inque(n, false); queue que; que.push(s); while (!que.empty()) { int from = que.front(); que.pop(); inque[from] = false; updated[from]++; if (updated[from] == n) { // exist negative cycle fill(dist.begin(), dist.end(), -INF); break; } for (Edges::const_iterator it = g[from].begin(); it != g[from].end(); it++) { if (it->capacity <= 0) { continue; } int to = it->dest; Weight cost = dist[from] + it->cost; if (cost < dist[to]) { dist[to] = cost; if (!inque[to]) { que.push(to); inque[to] = true; } } } } return dist; } ll n, m; vector incnt; vector outcnt; vector dists; inline int IN(int x) { return x; } inline int OUT(int x) { return n + x; } inline int SOURCE() { return 2 * n; } inline int DEST() { return 2 * n + 1; } inline int SIZE() { return 2 * n + 2; } int main() { while (scanf("%lld", &n) > 0 && n > 0) { incnt = vector(n, 0); outcnt = vector(n, 0); dists = vector(n); ll ans = 0; Graph baseG(n); int e = 0; REP(i, n) { ll k; int v = scanf("%lld", &k); assert(v == 1); REP(j, k) { ll t, c; int v = scanf("%lld %lld", &t, &c); t--; assert(v == 2); AddEdge(baseG, e, i, t, 1, c); incnt[t]++; outcnt[i]++; ans += c; } } vector ins; vector outs; dists[0] = SPFA(baseG, 0); REP(i, n) { if (incnt[i] == outcnt[i]) { continue; } if (incnt[i] > outcnt[i]) { ins.push_back(i); } else { outs.push_back(i); } dists[i] = SPFA(baseG, i); } Graph g(SIZE()); e = 0; FORIT(it1, ins) { FORIT(it2, outs) { if (dists[*it1][*it2] > (1LL << 50)) { continue; } AddEdge(g, e, IN(*it1), OUT(*it2), INF, dists[*it1][*it2]); } AddEdge(g, e, SOURCE(), IN(*it1), incnt[*it1] - outcnt[*it1], 0); } FORIT(it, outs) { AddEdge(g, e, SOURCE(), OUT(*it), INF, dists[0][*it]); AddEdge(g, e, OUT(*it), DEST(), outcnt[*it] - incnt[*it], 0); } ans += MinCostFlow(g, e, SOURCE(), DEST()).second; printf("%lld\n", ans); } }