Go: // ダイクストラのアルゴリズム
package main

import (
	"bufio"
	"fmt"
	"log"
	"math"
	"os"
	"strconv"
	"strings"
)

type color int

const (
	white color = iota // 未訪問
	mst                // MSTとして確定
)

// 頂点
type node struct {
	num       int         // 頂点の番号
	weights   map[int]int // 重みMAP
	parent    *node       // MSTへの重み最小の親
	distFromS int         // 始点からの距離
	color     color
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	n := eGetInt(scanner)

	nodes := make([]*node, n)
	for i := 0; i < n; i++ {
		weights := eAtoi((strings.Fields(eGetline(scanner))))
		v := &node{weights[0], make(map[int]int, weights[1]), nil, math.MaxInt32, white}
		for j := 0; j < weights[1]; j++ {
			k := weights[j*2+2] // 相手の頂点名
			w := weights[j*2+3] // 重み
			v.weights[k] = w
		}
		nodes[i] = v
	}

	// 初回はnode[0]がMSTに入るように
	nodes[0].distFromS = 0

	for { // 全部チェックするまで

		// どの頂点を新たにMSTに取り込むか

		var minNode *node
		min := math.MaxInt32
		for _, v := range nodes {
			if v.color == mst {
				continue
			}
			if v.distFromS < min {
				min = v.distFromS
				minNode = v
			}
		}
		if minNode == nil {
			// すべて完了している.
			break
		}

		// MSTに追加する頂点決定
		minNode.color = mst

		// fmt.Printf(">[%v]\n", minNode)
		// MSTに属していない頂点それぞれについて,Startからの最小の重みの距離を更新
		for i, v := range nodes {
			if v.color == mst {
				continue
			}
			w, ok := minNode.weights[i]
			if !ok {
				// minNodeと接してない
				continue
			}

			if minNode.distFromS+w < v.distFromS {
				// minNode経由の距離がもっとも重みが少ないので親を変更
				v.distFromS = minNode.distFromS + w
				v.parent = minNode
				// fmt.Printf("[%v %v]\n", v, minNode)
			}
		}
		// fmt.Printf("<\n")
	}

	for i, v := range nodes {
		fmt.Printf("%d %d\n", i, v.distFromS)
	}
}

func eGetInt(scanner *bufio.Scanner) int {
	t := eAtoi(strings.Fields(eGetline(scanner)))
	return t[0]
}

func eGetline(p *bufio.Scanner) string {
	if !p.Scan() {
		if err := p.Err(); err != nil {
			log.Fatal(err.Error())
		}
		return ""
	}
	return p.Text()
}

func eAtoi(s []string) []int {
	ints := make([]int, len(s))
	var err error
	for i, e := range s {
		ints[i], err = strconv.Atoi(e)
		if err != nil {
			log.Fatal(err.Error())
		}
	}
	return ints
}

C++: #include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = (a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (a); i >= (int)(b); i--)
#define all(x) (x).begin(), (x).end()
using i32 = int32_t;
using i64 = int64_t;
using f32 = float;
using f64 = double;
using P   = pair<int, int>;

template <class T>
bool chmin(T& a, T b) {
    if (a > b) {
        a = b;
        return true;
    } else {
        return false;
    }
}
template <class T>
bool chmax(T& a, T b) {
    if (a < b) {
        a = b;
        return true;
    } else {
        return false;
    }
}

template <class T>
void dump_vec(const vector<T>& v) {
    auto len = v.size();
    rep(i, 0, len) {
        cout << v[i] << (i == (int)len - 1 ? "\n" : " ");
    }
}

struct FastIO {
    FastIO() {
        cin.tie(0);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(20);
    }
} FASTIO;

//---------------------------------------------------------------------------------------------------

struct Edge {
    int from, to;
    i64 cost;
    Edge() {}
    Edge(int t, i64 c) : from(-1), to(t), cost(c) {}
    Edge(int f, int t, i64 c) : from(f), to(t), cost(c) {}

    bool operator<(const Edge& r) const {
        return cost < r.cost;
    }
    bool operator>(const Edge& r) const {
        return cost > r.cost;
    }
};

using Vertex = vector<Edge>;
using Graph  = vector<Vertex>;

// 無向
void link(Graph& g, int from, int to, int cost = 1) {
    g[from].push_back(Edge(from, to, cost));
    g[to].push_back(Edge(to, from, cost));
    return;
}

// 有向
void connect(Graph& g, int from, int to, int cost = 1) {
    g[from].push_back(Edge(from, to, cost));
    return;
}

vector<i64> dijkstra(const Graph& g, int start) {
    const auto inf = numeric_limits<i64>::max();
    vector<i64> dist(g.size(), inf);

    using Pi = pair<i64, int>;
    priority_queue<Pi, vector<Pi>, greater<Pi>> que;
    dist[start] = 0;
    que.push(make_pair(0, 0));
    while (!que.empty()) {
        const auto e    = que.top();
        const auto cost = e.first;
        const auto from = e.second;
        que.pop();
        if (dist[from] < cost) continue;

        for (const auto& e : g[from]) {
            const auto next_cost = e.cost + cost;
            if (chmin(dist[e.to], next_cost)) {
                que.push(make_pair(next_cost, e.to));
            }
        }
    }

    return dist;
}

//---------------------------------------------------------------------------------------------------

signed main() {
    int N;
    cin >> N;
    Graph G(N);
    rep(i, 0, N) {
        int u, k;
        cin >> u >> k;
        rep(j, 0, k) {
            int v, c;
            cin >> v >> c;
            connect(G, u, v, c);
        }
    }
    auto dist = dijkstra(G, 0);
    rep(i, 0, N) {
        cout << i << " " << dist[i] << "\n";
    }
}