Go: package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

const (
	MAX_N      = 100
	MAX_WEIGHT = 100000
)

type Edge struct {
	start  int
	end    int
	weight int
}

type ShortestInfo struct {
	edges    []Edge
	shortest int
}

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

	n, err := nextInt(sc)
	if err != nil {
		panic(err)
	}

	shortestList := make([]ShortestInfo, n)
	for i := 1; i < n; i++ {
		shortestList[i] = ShortestInfo{edges: []Edge{}, shortest: MAX_N*MAX_WEIGHT + 1}
	}

	adjacentMatrix, err := createAdjacentMatrix(n, sc)
	if err != nil {
		panic(err)
	}

	sssp([]int{1}, shortestList, adjacentMatrix)
	for _, v := range shortestList {
		fmt.Printf("%d %d\n", v.getEnd()-1, v.shortest)
	}
}

func (si ShortestInfo) getEnd() int {
	if len(si.edges) == 0 {
		return 1
	} else {
		return si.edges[len(si.edges)-1].end
	}
}

func createAdjacentMatrix(n int, sc *bufio.Scanner) ([][]int, error) {
	adjacentMatrix := make([][]int, n)
	for i := 0; i < n; i++ {
		id, err := nextInt(sc)
		if err != nil {
			return nil, err
		}
		adjacentMatrix[id] = make([]int, n)
		for j := 0; j < n; j++ {
			adjacentMatrix[id][j] = -1
		}
		vertexNum, err := nextInt(sc)
		if err != nil {
			return nil, err
		}
		for j := 0; j < vertexNum; j++ {
			v, err := nextInt(sc)
			if err != nil {
				return nil, err
			}
			c, err := nextInt(sc)
			if err != nil {
				return nil, err
			}
			adjacentMatrix[id][v] = c
		}
	}
	return adjacentMatrix, nil
}

func sssp(nodeStack []int, shortestList []ShortestInfo, adjacentMatrix [][]int) {
	for len(nodeStack) > 0 {
		currentNode := nodeStack[0]
		nodeStack = nodeStack[1:]
		currentShortest := getShortest(currentNode, shortestList)
		adjacents := findAdjacents(currentNode, adjacentMatrix)
		for i := 0; i < len(adjacents); i++ {
			adj := adjacents[i]
			if currentShortest.shortest+adj.weight < getShortest(adj.end, shortestList).shortest {
				setShortest(adj.end, adj, currentShortest, shortestList)
				nodeStack = append(nodeStack, adj.end)
			}
		}
	}
}

func getShortest(node int, shortestList []ShortestInfo) ShortestInfo {
	return shortestList[node-1]
}

func setShortest(node int, edge Edge, currentShortest ShortestInfo, shortestList []ShortestInfo) {
	newEdges := make([]Edge, len(currentShortest.edges)+1)
	for i := 0; i < len(newEdges)-1; i++ {
		newEdges[i] = currentShortest.edges[i]
	}
	newEdges[len(newEdges)-1] = edge
	shortestInfo := ShortestInfo{edges: newEdges, shortest: currentShortest.shortest + edge.weight}
	shortestList[node-1] = shortestInfo
}

func findAdjacents(currentNode int, adjacentMatrix [][]int) []Edge {
	adjacents := adjacentMatrix[currentNode-1]
	edges := []Edge{}
	for i, v := range adjacents {
		if v > 0 {
			edges = append(edges, Edge{start: currentNode, end: i + 1, weight: v})
		}
	}
	return edges
}

func nextInt(sc *bufio.Scanner) (int, error) {
	sc.Scan()
	return strconv.Atoi(sc.Text())
}

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

#define NODE_NUM 100

class Node
{
private:
	int next_node_list[NODE_NUM];
	int next_node_num;
	int next_weight_list[NODE_NUM];
public:
	Node();
	void AddNextNode(int id, int weight);
	void SetWeight(int weight);
	void DistributeWeight();
	int weight_from_0;
	bool check;
	int id;
};

Node::Node()
{
	next_node_num = 0;
	weight_from_0 = -1;
	check = false;
}

Node *Node_list;
priority_queue<Node, vector<Node>, greater<Node> > que;
bool operator> (const Node &n1, const Node &n2){
	return n1.weight_from_0 > n2.weight_from_0;
};

void Node::AddNextNode(int id, int weight)
{
	next_node_list[next_node_num] = id;
	next_weight_list[next_node_num] = weight;
	next_node_num++;
}

void Node::SetWeight(int weight)
{
	if (weight_from_0 == -1 || weight < weight_from_0) {
		weight_from_0 = weight;
	}
}

void Node::DistributeWeight()
{
	check = true;
	for (int i = 0; i < next_node_num; i++) {
		if (Node_list[next_node_list[i]].check == false) {
			Node_list[next_node_list[i]].SetWeight(weight_from_0 + next_weight_list[i]);
			que.push(Node_list[next_node_list[i]]);
		}
	}
}

int main(void)
{
	//input
	int n;
	cin >> n;
	Node_list = new Node[n]();
	for (int i = 0; i < n; i++) {
		Node_list[i].id = i;
		int u, k;
		cin >> u >> k;
		for (int j = 0; j < k; j++) {
			int v, c;
			cin >> v >> c;
			Node_list[i].AddNextNode(v, c);
		}
	}

	//weight from 0 ?
	Node_list[0].check = true;
	Node_list[0].weight_from_0 = 0;
	Node_list[0].DistributeWeight();
	while (!que.empty()) {
		int id = que.top().id;
		que.pop();
		Node_list[id].DistributeWeight();
	}

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

C++: #define _USE_MATH_DEFINES
#include<iostream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<cmath>
#include<vector>
#include<deque>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define str string
#define ld long double
#define vec vector
#define vll vec<ll>
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define rrep(i,b,a) for(ll i=b;i>=a;i--)
#define ALL(a) a.begin(),a.end()
#define rALL(a) a.rbegin(),a.rend()
#define kai "\n"
#define yuque priority_queue
#define ryuque(t) priority_queue<t,vec<t>,greater<t>>
#define pub push_back
#define pob pop_back
#define puf push_front
#define pof pop_front
#define mie min_element
#define mae max_element
#define tos to_string
#define sep setprecision
#define MOD 1000000007ll
using namespace std;
void solve();
int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
	cout<<fixed;
	solve();
}

//nCk(mod p)
const ll NUM=2;
ll fac[NUM],finv[NUM],inv[NUM];
void cmodf(ll p=MOD){
	fac[0]=fac[1]=1;
	finv[0]=finv[1]=1;
	inv[1]=1;
	rep(i,2,NUM){
		fac[i]=fac[i-1]*i%p;
		inv[i]=p-inv[p%i]*(p/i)%p;
		finv[i]=finv[i-1]*inv[i]%p;
	}
}
ll cmod(ll n,ll k,ll p=MOD){
	return fac[n]*(finv[k]*finv[n-k]%p)%p;
}

//最大公約数
ll gcd(ll n,ll m){
	ll k=n%m;
	while(k!=0){n=m;m=k;k=n%m;}
	return m;
}
ll gcd(vector<ll> a){
	rep(i,1,a.size()){
		ll k=a[i-1]%a[i];
		while(k!=0){
			a[i-1]=a[i];
			a[i]=k;
			k=a[i-1]%a[i];
		}
	}
	return a.back();
}

//最小公倍数
ll lcm(ll n,ll m){
	ll t=n*m,k=n%m;
	while(k!=0){n=m;m=k;k=n%m;}
	return t/m;
}
ll lcm(vector<ll> a){
	ll n;
	rep(i,1,a.size()){
		n=a[i-1]*a[i];
		ll k=a[i-1]%a[i];
		while(k!=0){
			a[i-1]=a[i];
			a[i]=k;
			k=a[i-1]%a[i];
		}
		n/=a[i];
		a[i]=n;
	}
	return n;
}

//keyの小さい方から探していった時に初めてvalueがjoken以上になる時のkey（keyが増えたらvalueも増えるか同じになるとき）
ll value(ll key) {
	/*変更*/
	return 0;
}
ll mink(ll lkey,ll rkey/*ここも調べる*/,ll joken){
	ll mkey;
	while(lkey!=rkey){
		mkey=(lkey+rkey)/2;
		if(value(mkey)>=joken)rkey=mkey;
		else lkey=mkey+1;
	}
	return rkey;
}

//ペア配列の整理
struct pea{
	ll f,s;
	bool operator<(const pea &c)const{
		return f!=c.f?f<c.f:s<c.s;
	};
};

//変数定義

//再帰関数

//アルゴリズム
void solve(){
	ll n;cin>>n;
	vec<vll> we(n,vll(n,MOD));
	vec<set<ll>> ch(n);
	vec<vll> pa(n);
	rep(i,0,n){
		ll u,k;cin>>u>>k;
		rep(j,0,k){
			ll v,c;cin>>v>>c;
			ch[u].insert(v);
			pa[v].pub(u);
			we[u][v]=c;
		}
	}
	vll a,ans(n);
	ans[0]=0;
	a.pub(0);
	rep(i,0,pa[0].size())ch[pa[0][i]].erase(0);
	while(a.size()!=n){
		ll m=MOD;ll jj;
		rep(i,0,a.size()){
			for(auto j=ch[a[i]].begin();j!=ch[a[i]].end();j++){
				if(ans[a[i]]+we[a[i]][*j]<m){
					m=ans[a[i]]+we[a[i]][*j];
					jj=*j;
				}
			}
		}
		ans[jj]=m;
		a.pub(jj);
		rep(i,0,pa[jj].size())ch[pa[jj][i]].erase(jj);
	}
	rep(i,0,n){
		cout<<i<<' '<<ans[i]<<kai;
	}
}