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<cstdio>
#include<cstdlib>
#include<cstring>
#include<stack>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>

#include<queue>

using namespace std;

static const int MAX_N = 10000;
static const int INFTY = (1 <<21);
static const int WHITE = 0;
static const int GRAY = 1;
static const int BLACK = 2;

class q_element
{
    public:
        // 各頂点のNo.と経路の値
        int vertex_num;
        int vertex_val;

        // コンストラクタ
        q_element(int a, int b)
        {
            vertex_num = a;
            vertex_val = b;
        };
};

// ">" のオーバーロード [ receive_val ] を基準に大小比較を行う
bool operator> (const q_element &q_element_1, const q_element &q_element_2)
{
    return q_element_1.vertex_val > q_element_2.vertex_val;
};

// q_elementクラスのオブジェクトを昇順にするためのキューの定義
std::priority_queue< q_element,
                     std::vector<q_element>,
                     std::greater<q_element> > pqEle;

// 隣接リストを作成する
vector<int> v_Link[MAX_N + 1];

int n, M[MAX_N][MAX_N];

// ダイクストラ法を実施するメソッド( 優先度付きキュー )
int Dijkstra_priority_queue();

int main(void)
{

    cin >> n;

    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            // 配列の初期化
            M[i][j] = INFTY;
        }
    }

    int k, c, u, v;

    for(int i = 0; i < n; i++)
    {
        cin >> u >> k;

        for(int j = 0; j < k; j++)
        {
            cin >> v >> c;

            // 隣接リストの作成
            v_Link[u].push_back(v);
            // 辺の値の代入
            M[u][v] = c;
        }
    }

    // 優先度付きキューを用いたダイクストラ法
    Dijkstra_priority_queue();

    return 0;

}

// 優先度付きキューを用いたダイクストラ法を実施するメソッド
int Dijkstra_priority_queue()
{
    int u, v, minv;
    int d[MAX_N], p[MAX_N], color[MAX_N];

    for(int i = 0; i < n; i++)
    {
        d[i] = INFTY;
        p[i] = -1;
        color[i] = WHITE;
    }

    // 初期値の設定
    d[0] = 0;
    color[0] = GRAY;
    // キューに要素を入れる
    pqEle.push( q_element(0, 0) );

    while( !pqEle.empty() )
    {
        //minv = INFTY;
        // 次に移動するべき頂点
        //u = -1;

        // 最小の値を持つ要素を取り出す ( キューの先頭 )
        u = pqEle.top().vertex_num;
        minv = pqEle.top().vertex_val;
        pqEle.pop();

        // 訪問完了
        color[u] = BLACK;

        for(int v_num = 0; v_num < v_Link[u].size(); v_num++)
        {
            // 隣接リストから要素を取得する
            v = v_Link[u][v_num];

            if( color[v] != BLACK )
            {
                // u → v の経路の中で, vのコストが最小のものが見つかれば更新する
                if( d[v] > d[u] + M[u][v] )
                {
                    // コストの記録
                    d[v] = d[u] + M[u][v];
                    // 頂点 v の親を記録する
                    p[v] = u;
                    // 訪問状態の記録
                    color[v] = GRAY;

                    // キューに要素を入れる
                    pqEle.push( q_element(v, d[v]) );
                }
            }
        }
    }

    // 結果の表示
    for(int i = 0; i < n; i++)
    {
        cout << i << " " << ( d[i] == INFTY ? -1 : d[i] ) << endl;
    }

    return 0;
}