Go: package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
	"strconv"
)

//make priority queue
type Item struct {
	id       int
	priority int // this state is priority and distans from start
	index    int
}

type PriorityQueue []*Item

func (pq PriorityQueue) Len() int { return len(pq) }

// we want the ascending-priority-queue.
// So we use less than here.
func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].priority < pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = j
	pq[j].index = i
}

func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*Item)
	item.index = n
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	item.index = -1 //for safety
	*pq = old[0 : n-1]
	return item
}

func (pq *PriorityQueue) update(dist int, id int) {
	for _, i := range *pq {
		if i.id == id {
			if i.priority > dist {
				i.priority = dist
			}
		}
	}
}

// the main code
func nextInt(sc *bufio.Scanner) int {
	sc.Scan()
	n, _ := strconv.Atoi(sc.Text())
	return n
}

func dikstra(dist *[][]int, n int) *[]int {
	// preparate priority queue
	inf := 1 << 30
	pq := make(PriorityQueue, n)
	shortests := make([]int, n)
	for i := 0; i < n; i++ {
		pq[i] = &Item{
			id:       i,
			priority: inf,
			index:    i,
		}

		shortests[i] = inf
	}
	pq[0].priority = 0
	shortests[0] = 0
	heap.Init(&pq)

	for pq.Len() > 0 {
		item := heap.Pop(&pq).(*Item)
		shortests[item.id] = item.priority
		for id, d := range (*dist)[item.id] {
			if d != -1 {
				pq.update(item.priority+d, id)
			}
		}
		heap.Init(&pq)
	}
	return &shortests
}

func main() {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)

	// init
	n := nextInt(sc)
	dist := make([][]int, n)
	for i := 0; i < n; i++ {
		dist[i] = make([]int, n)
		for j := 0; j < n; j++ {
			dist[i][j] = -1
		}
	}

	// std Input
	for i := 0; i < n; i++ {
		u := nextInt(sc)
		k := nextInt(sc)
		for j := 0; j < k; j++ {
			v, c := nextInt(sc), nextInt(sc)
			dist[u][v] = c
		}
	}

	shortests := dikstra(&dist, n)
	for i, d := range *shortests {
		fmt.Printf("%d %d\n", i, d)
	}
}

C++: /**
 * @brief 単一始点最短路問題をDijkstra法で解く
 */


// ********************************************************************************
// Include files
// ********************************************************************************
#include <iostream>
#include <limits>
#include <vector>
#include <queue>


// ********************************************************************************
// Type synonyms
// ********************************************************************************
using weight_t = int32_t;  // 辺(u, v)への重みwを表す型
using index_t  = int32_t;  // 頂点vの添字を表す型


// ********************************************************************************
// Constants
// ********************************************************************************
static constexpr weight_t INF = std::numeric_limits<weight_t>::max() / 3;  // 辺が存在しない場合に使用される値
static constexpr index_t  NIL = std::numeric_limits<index_t>::min()  / 3;  // 先行点が存在しない場合に使用される値

/**
 * @brief       頂点色列挙体
 * @details     (u, v) ∈ E で頂点uが黒ならば頂点vは灰か黒である。(ただしEはグラフの辺集合)
 *              すなわち、黒頂点に隣接するすべての頂点は発見済みである。
 *              灰頂点は白頂点に隣接することがあり、これらの頂点が既発見頂点と未発見頂点の境界をなす。
 */
enum vcolor : int32_t {
    WHITE,  // 未発見頂点
    BLACK,  // 既発見頂点
    GRAY,   // 既発見頂点
};


// ********************************************************************************
// Structs
// ********************************************************************************
/**< @brief グラフ用ノード(頂点) */
struct vertex {
    weight_t d;     // 始点sからの距離
    index_t pi;     // 先行頂点(の添字)
    vcolor color;   // 頂点の色
};

/**
 * @brief グラフ用エッジ(辺)
 * @note  G = (V, E)を重み関数wを持つ重み付きグラフとすると、
 *        辺(u, v) ∈ Eの重みはw(u, v)と表される。
 */
struct edge {
    index_t   src;  // 辺の始点u
    index_t   dst;  // 辺の終点v
    weight_t  w;    // 辺(u, v)の重み(コスト)
};

/**< @brief 最短路推定値をもつ頂点 (∈V-SでVはグラフの頂点集合, Sは始点sからの最短路重みが最終的に決定された頂点集合) */
struct state {
    index_t  u; // G.Vに属する頂点u
    weight_t d; // 始点sからの距離d

    // <演算子オーバーロード
    bool operator < (const state& s) const { 
        return d > s.d;     // min優先度付きキューのためのREVERSE
    }

    state(index_t u, weight_t d) : u(u), d(d) {}
};


// ********************************************************************************
// Type synonyms (part2)
// ********************************************************************************
using edges_t       = std::vector<edge>;    // グラフG=(V, E)の辺集合E
using vertices_t    = std::vector<vertex>;  // グラフG=(V, E)の頂点集合V
using graph_t       = std::vector<edges_t>; // グラフGの隣接リスト表現


// ********************************************************************************
// Functions
// ********************************************************************************

/**
 * @brief           最短路推定値dと先行点piおよび頂点色colorを初期化する
 *
 * @param[out]      vertices_t& V      グラフの頂点集合V
 * @param[in]       index_t     s      始点s
 *
 * @details         初期化の後、すべてのv∈Vについてv.pi=NIL
 *                  すべてのv∈V-{s}についてv.d=INF, v.color=WHITEである。
 */
void init(vertices_t& V, index_t s)
{
    for (auto&& v : V) {
        v.d     = INF;
        v.pi    = NIL;
        v.color = WHITE;
    }

    V[s].d     = 0;
    V[s].color = GRAY;
}

/**
 * @brief           uを経由することで、vへの既知の最短路を改善できるか判定し、
 *                  できるならば、v.dとv.piおよびv.colorを更新する。
 *                  また緩和(更新)された場合、優先度付きキューQに挿入しておく。
 *
 * @param[inout]    vertices_t&                 V   グラフの頂点集合V
 * @param[in]       const edge&                 e   辺(u, v)
 * @param[out]      std::priority_queue<state>& Q   min優先度付きキュー
 *
 * @details         緩和操作は制約v.d <= u.d + w(u, v)の緩和とみなすことができる。
 *                  最短路の性質から任意の辺(u,v)∈Eに対してδ(s,v)<=δ(s,u)+w(u,v)が成立する。
 *                  この制約はu.d=δ(s,u)かつv.d=δ(s,v)のとき必ず成立している必要がある。
 *                  v.d=u.d+w(u,v)ならばこの制約を満たさなければならないというプレッシャーが存在しないので
 *                  この制約は緩和されたことになる。(ただし、δ(s,v)は始点sから頂点vへの最短路重みを表す。)
 */
void relax(vertices_t& V, const edge& e, std::priority_queue<state>& Q)
{
    index_t u = e.src;
    index_t v = e.dst;

    // 既知の最短路を改善できるか判定する。
    if (   V[v].color != BLACK
        && V[u].d + e.w < V[v].d  ) {   // 改善できるならば、

        // 緩和を行う
        V[v].d      = V[u].d + e.w;
        V[v].pi     = u;
        V[v].color  = GRAY;

        Q.emplace(v, V[v].d);
    }
}

/**
 * @brief           単一始点最短路問題をDijkstra法で解く。
 * @param[in]       const graph_t&  G  非負の重み付き有向グラフG
 * @param[in]       index_t         s  始点s
 * @return          始点sからの最短路重みが最終的に決定された頂点の集合S
 *
 * @details         Dijkstraのアルゴリズムは、始点sからの最短路重みが最終的に決定された頂点の集合Sを管理する。
 *                  アルゴリズムは繰り返し、最小の最短路推定値を持つ頂点u∈V-Sを選択し、uをSに追加し、
 *                  uから出るすべての辺を緩和する。
 */
vertices_t dijkstra(const graph_t& G, index_t s)
{
    vertices_t S(G.size());
    std::priority_queue<state> Q;

    init(S, s);             // すべての頂点のd値とpi値を初期化する。
    Q.emplace(s, S[s].d);   // このループの最初の実行ではu=sである。
    while (!Q.empty()) {

        // Qから最小の最短路推定値を持つ頂点u(∈V-S)を取得する
        state p = Q.top();
        Q.pop();
        index_t  u = p.u;
        weight_t d = p.d;

        // 更新する必要がないならば飛ばす
        if (S[u].d < d) {
            continue;
        }

        // 黒頂点は集合Sに属する
        S[u].color = BLACK;

        // 頂点uの隣接リストに関してループをまわす
        for (const auto& e : G[u]) {    // 頂点uからでる辺(u, v)をそれぞれ緩和し、
            relax(S, e, Q);             // uを経由することでvへの最短路が改善できる場合にはv.dとv.piを更新する
        }
    }

    return S;
}


// ********************************************************************************
// Entry point
// ********************************************************************************

int main()
{
    graph_t G;
    int n, k, u, v, c;
    
    std::cin >> n;
    G.resize(n);
    for (int i = 0; i < n; i++) {
        std::cin >> u >> k;
        G[u].resize(k);
        for (int j = 0; j < k; j++) {
            cin >> v >> c;
            G[u][j].src = u;
            G[u][j].dst = v;
            G[u][j].w   = c;
        }
    }

    vertices_t S = dijkstra(G, 0);
    for (int i = 0; i < n; i++) {
        std::cout << i << " " << S[i].d << std::endl; 
    }
    return 0;
}