Go: package main

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

const NIL = -1

type Node struct {
	id     int
	weight int
}

func init() {
	sc.Split(bufio.ScanWords)
}

type NodeHeap []Node

func (h NodeHeap) Len() int           { return len(h) }
func (h NodeHeap) Less(i, j int) bool { return h[i].weight < h[j].weight }
func (h NodeHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *NodeHeap) Push(x interface{}) {
	*h = append(*h, x.(Node))
}

func (h *NodeHeap) Pop() interface{} {
	old := *h
	n := len(old)
	x := old[n-1]
	*h = old[0 : n-1]
	return x
}

var sc = bufio.NewScanner(os.Stdin)

func scanInt() int {
	num, _ := strconv.Atoi(scanString())
	return num
}

func scanString() string {
	sc.Scan()
	return sc.Text()
}

func init() {
	sc.Split(bufio.ScanWords)
}

func main() {
	n := scanInt()

	route := make([][]Node, n)
	weight := make([]int, n)
	for i := 0; i < n; i++ {
		weight[i] = NIL
	}

	for i := 0; i < n; i++ {
		u := scanInt()
		k := scanInt()
		route[i] = make([]Node, k)
		for j := 0; j < k; j++ {
			route[u][j] = Node{id: scanInt(), weight: scanInt()}
		}
	}

	start := Node{id: 0, weight: 0}
	h := &NodeHeap{start}
	heap.Init(h)

	for h.Len() > 0 {
		node := heap.Pop(h).(Node)
		if weight[node.id] != NIL {
			continue
		}
		weight[node.id] = node.weight

		for _, nextNode := range route[node.id] {
			if weight[nextNode.id] != NIL {
				continue
			}
			nextNode.weight += node.weight
			heap.Push(h, nextNode)
		}
	}

	for i, w := range weight {
		fmt.Println(i, w)
	}
}

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;
// }}}

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

int N;
int G[10000][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;

        REP(v, N) {
            if(done[v]) continue;
            if(G[minv][v] == -1) continue;
            int cost_new = cost[minv] + G[minv][v];
            if(cost_new < cost[v]) {
                cost[v] = cost_new;
            }
        }
    }

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

int main()
{
    cin >> N;
    REP(from, N) {
        REP(to, N) {
            G[from][to] = -1;
        }
    }

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

    solve();

    return 0;
}

C++: #include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
using namespace std;

//typedef vector<int> VI;
//typedef vector<VI> VVI;
//typedef vector<string> VS;
//typedef stack<int> SI;
//typedef queue<int> QI;
typedef pair<int,int> PII;
//typedef long long LL;

//#define d(x)  cout<<#x<<" = "<<(x)<<endl;
//#define ALL(a)  (a).begin(),(a).end()
//#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define EMP empty()
#define SZ(a) int((a).size())
//#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
//#define REACH(i,c) for(typeof((c).rbegin()) i=(c).rbegin(); i!=(c).rend(); ++i)
//#define EXIST(s,e) ((s).find(e)!=(s).end())
//#define SORT(c,n) sort(c,c+n)
//#define VSORT(c) sort((c).begin(),(c).end())
//#define FOR(i,a,b) for(int i=(a);i<(b);++i)
//#define REP(i,n)  FOR(i,0,n)
//#define DFOR(i,b,a) for(int i=(b)-1;i>=(a);--i)
//#define DREP(i,n) DFOR(i,n,0)
//#define INF 1000000000

//const double EPS = 1e-10;
//const double PI  = acos(-1.0);
////////////////////////////////////////////////
static const int MAX=10000;
static const int INF=(1<<20);
static const int WHITE=0;
static const int GRAY=1;
static const int BLACK=2;

int n;
vector<PII> adj[MAX];
void dijkstra()
{
	priority_queue<PII> PQ;
	int color[MAX];
	int d[MAX];
	for(int i=0;i<n;i++)
	{
		d[i]=INF;
		color[i]=WHITE;
	}
	
	d[0]=0;
	PQ.push(MP(0,0));
	color[0]=GRAY;
	
	while(!PQ.EMP)
	{
		PII f=PQ.top();
		PQ.pop();
		int u=f.second;
		color[u]=BLACK;
		
		if(d[u]<f.first*(-1))continue;
		
		for(int j=0;j<SZ(adj[u]);j++)
		{
			int v=adj[u][j].first;
			if(color[v]==BLACK)continue;
			if(d[v]>d[u]+adj[u][j].second)
			{
				d[v]=d[u]+adj[u][j].second;
			}
			PQ.push(MP(d[v]*(-1),v));
			color[v]=GRAY;
		}
	}
	for(int i=0;i<n;i++)
	{
		cout<<i<<" "<<(d[i]==INF?-1:d[i])<<endl;
	}
}

int main()
{
	int k,u,c,v;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>u>>k;
		for(int j=0;j<k;j++)
		{
			cin>>v>>c;
			adj[u].PB(MP(v,c));
		}
	}
	
	dijkstra();
	
	return 0;
}

C++: #include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <string>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <algorithm>

using namespace std;

// ---------------------
// repetition
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)

// debug
#define dump(x)  cerr << #x << " = " << (x) << endl;
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl;

// ---------------------
#define INF (1 << 21)
typedef long long ll;

int main() {
  int n;
  cin >> n;

  vector<int> V[n];
  // int E[n][n];
  map<pair<int, int>, int> E;
  int d[n];
  int visited[n];

  REP(x, n) {
    REP(y, n) {
      // E[x][y] = INF;
      // E[make_pair(x, y)] = INF;
    }
    d[x] = INF;
    visited[x] = 0;
  }

  REP(_, n) {
    int u, k;
    cin >> u >> k;
    REP(__, k) {
      int v, c;
      cin >> v >> c;
      V[u].push_back(v);
      // E[u][v] = c;
      E[make_pair(u, v)] = c;
      // E[v][u] = c;
    }
  }

  d[0] = 0;
  REP(_, n) {
    int minv = -1;
    int mincost = INF;
    REP(v, n) {
      if (!visited[v] && d[v] < mincost) {
        minv = v;
        mincost = d[v];
      }
    }
    visited[minv] = 1;
    for (vector<int>::iterator it = V[minv].begin(); it != V[minv].end(); it++) {
      if (E[make_pair(minv, *it)] < INF && d[minv] + E[make_pair(minv, *it)] < d[*it]) {
        d[*it] = d[minv] + E[make_pair(minv, *it)];
      }
    }
  }

  REP(i, n) {
    cout << i << " " << d[i] << endl;
  }
  return 0;
}