Go: package main

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

type Node struct {
	Id int
	Dis int
}

type PriorityQueue []*Node

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

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].Dis < pq[j].Dis
}

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

func (pq *PriorityQueue) Push(x interface{}) {
	*pq = append(*pq, x.(*Node))
}

func (pq *PriorityQueue) Pop() interface{} {
	n := len(*pq)
	pop := (*pq)[n-1]
	*pq = (*pq)[0:n-1]
	return pop
}

func main() {
	var n int
	fmt.Scan(&n)

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

	g := make([][]int, n)
	c := make([][]int, n)
	pq := make(PriorityQueue, 0, n)
	d := make([]int, n)
	for i := 0; i < n; i++ {
		sc.Scan()
		u, _ := strconv.Atoi(sc.Text())
		sc.Scan()
		k, _ := strconv.Atoi(sc.Text())
		g[u] = make([]int, k)
		c[u] = make([]int, k)
		for j := 0; j < k; j++ {
			sc.Scan()
			g[u][j], _ = strconv.Atoi(sc.Text())
			sc.Scan()
			c[u][j], _ = strconv.Atoi(sc.Text())
		}

		if u == 0 {
			d[u] = 0
		} else {
			d[u] = 1 << 30
		}
		pq.Push(&Node{u, d[u]})
	}
	heap.Init(&pq)

	for pq.Len() > 0 {
		node := heap.Pop(&pq).(*Node)
		for i := 0; i < len(g[node.Id]); i++ {
			nextId := g[node.Id][i]
			nextDis := node.Dis + c[node.Id][i]
			if nextDis < d[nextId] {
				d[nextId] = nextDis
				heap.Push(&pq, &Node{nextId, nextDis})
			}
		}
	}

	wr := bufio.NewWriter(os.Stdout)
	for i := 0; i < n; i++ {
		wr.WriteString(strconv.Itoa(i))
		wr.WriteString(" ")
		wr.WriteString(strconv.Itoa(d[i]))
		wr.WriteString("\n")
	}
	wr.Flush()
}

C++: #include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;

#define INF 2000000000

struct edge{ int to, cost;};
struct P{ int d, to;};

int n;
int sz = 0; //heap size
P heap[20000];
vector<edge> G[10000]; //adjacency list
int d[10000];

//minimum heap
void push(P x){
  
  int i = sz++;
  
  while(i > 0){
    int p = (i - 1) / 2;
    
    if(heap[p].d <= x.d) break;
    
    heap[i] = heap[p];
    i = p;
  }
  
  heap[i] = x;
}

P pop(){
  
  P ret = heap[0];
  P x = heap[--sz];
  
  int i = 0;
  while(i * 2 + 1 < sz){
    
    int a = i * 2 + 1, b = i * 2 + 2;
    if(b < sz && heap[b].d < heap[a].d) a = b;
    
    if(heap[a].d >= x.d) break;
    
    heap[i] = heap[a];
    i = a;
  }
  
  heap[i] = x;
  
  return ret;
}

void dijkstra(int s){

  //initialization
  for(int i = 0;i < n;i++) d[i] = INF;
  d[s] = 0;
  push((P){0, s});
  
  while(sz){
    P p = pop();
    int v = p.to;
    
    if(d[v] < p.d) continue;
    for(int i = 0;i < (int)G[v].size();i++){
      edge e = G[v][i];
      if(d[e.to] > d[v] + e.cost){
        d[e.to] = d[v] + e.cost;
        push((P){d[e.to], e.to});
      }
    }
  }
}

int main(){
  
  int u, k;
  edge e;

  //input
  cin >> n;
  for(int i = 0;i < n;i++){
    cin >> u >> k;
    for(int j = 0;j < k;j++){
      cin >> e.to >> e.cost;
      G[u].push_back(e);
    }
  }
  
  dijkstra(0);

  //output
  for(int i = 0;i < n;i++) cout << i << " " << d[i] << endl;
  
  return 0;
}

C++: #include <stdio.h>
#include <iostream>
#include <vector>
#include <tuple>
#include <queue>
using namespace std;

#define NUM 100
#define NIL -1
#define INF 1000000000
#define WHITE 0
#define BLACK 1
int node_num;
vector<tuple<int, int>> G[NUM];
priority_queue<tuple<int, int>> PQ;
int V[NUM];
int color[NUM];

void init(void){
    scanf("%d", &node_num);

    for(int i = 0; i < node_num; i++){
        int u, k;
        scanf("%d", &u);
        scanf("%d", &k);

        for(int j = 0; j < k; j++){
            int v_, c;
            scanf("%d", &v_);
            scanf("%d", &c);
            G[u].push_back(make_tuple(v_, c));
        }
    }

    for(int i = 0; i < node_num; i++){
        color[i] = WHITE;
        V[i] = INF;
    }
}

void updateAround(int n){
    color[n] = BLACK;
    for(int i = 0; i < G[n].size(); i++){
        int old_dist = V[get<0>(G[n][i])];
        int new_dist = V[n] + get<1>(G[n][i]);
        if (new_dist < old_dist){
            V[get<0>(G[n][i])] = min(new_dist, old_dist);
            PQ.push(make_tuple(V[get<0>(G[n][i])], get<0>(G[n][i])));
        }
    }

    int min_index = NIL;
    int min_value = INF;
    while(!PQ.empty()){
        tuple<int, int> f = PQ.top(); PQ.pop();
        if(color[get<1>(f)] == BLACK){
            continue;
        }
        min_value = get<0>(f);
        min_index = get<1>(f);
    }

    if(min_index != NIL){
        updateAround(min_index);
    }
}

int main(void){
    init();

    V[0] = 0;
    updateAround(0);

    for(int i = 0; i < node_num; i++){
        printf("%d %d\n", i, V[i]);
    }
}

C++: // #include {{{
#include <array>
#include <vector>
#include <deque>
#include <queue>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <string>
#include <algorithm>
#include <numeric>
#include <functional>
#include <iterator>
#include <tuple>
#include <utility>
#include <random>
#include <limits>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cstdint>
#include <cassert>
// }}}

using namespace std;

// macros {{{
template<typename T, size_t N>
constexpr size_t NELEMS(T (&)[N]) { return N; }

template<typename InputIt>
void PRINT_RANGE(InputIt first, InputIt last)
{
    for(; first != last; ++first)
        cout << *first << (first==last ? "" : " ");
    cout << "\n";
}

template<typename T>
void PRINT_MATRIX(T mat, size_t nr, size_t nc)
{
    for(size_t r = 0; r < nr; ++r) {
        for(size_t c = 0; c < nc; ++c) {
            cout << mat[r][c] << (c==nc-1 ? "" : " ");
        }
        cout << "\n";
    }
}

#define FOR(i, start, end) for(int i = (start); i < (end); ++i)
#define REP(i, n) FOR(i, 0, n)
// }}}

// types {{{
using ll  = long long;
using ull = unsigned long long;
// }}}

struct Edge {
    int to;
    int cost;
    Edge(int to_arg, int cost_arg) : to(to_arg), cost(cost_arg) {}
};

constexpr int INF = numeric_limits<int>::max();

int N;
vector<Edge> G[10000];

void solve()
{
    vector<int> cost(N);
    deque<bool> done(N);

    fill(begin(cost), end(cost), INF);
    cost[0] = 0;

    for(;;) {
        int mincost = INF;
        int minv    = -1;

        REP(v, N) {
            if(done[v]) continue;
            if(cost[v] < mincost) {
                mincost = cost[v];
                minv    = v;
            }
        }

        if(minv == -1) break;

        done[minv] = true;

        for(const Edge& e : G[minv]) {
            if(done[e.to]) continue;
            int cost_new = cost[minv] + e.cost;
            if(cost_new < cost[e.to]) {
                cost[e.to] = cost_new;
            }
        }
    }

    REP(v, N) {
        cout << v << " " << cost[v] << "\n";
    }
}

int main()
{
    cin >> N;
    REP(_, N) {
        int from, k;
        cin >> from >> k;
        REP(_, k) {
            int to, cost;
            cin >> to >> cost;
            G[from].emplace_back(to, cost);
        }
    }

    solve();

    return 0;
}