Go: package main

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

var sc = bufio.NewScanner(os.Stdin)

const T = 10000000

var n int
var A [101][101]int

func nextInt() int {
	sc.Scan()
	i, _ := strconv.Atoi(sc.Text())
	return i
}
func Shortestsearch() {
	var Minimum int
	var d, color [100]int
	var u int

	for i := 0; i < n; i++ {
		d[i] = T
		color[i] = 0
	}

	d[0] = 0
	color[0] = 1

	for {
		Minimum = T
		u = -1
		for i := 0; i < n; i++ {
			if Minimum > d[i] && color[i] != 2 {
				u = i
				Minimum = d[i]
			}
		}
		if u == -1 {
			break
		}
		color[u] = 2
		for j := 0; j < n; j++ {
			if color[j] != 2 && A[u][j] != T {
				if d[j] > d[u]+A[u][j] {
					d[j] = d[u] + A[u][j]
					color[j] = 1
				}
			}
		}
	}
	for i := 0; i < n; i++ {
		fmt.Printf("%d %d\n", i, d[i])
	}
}
func main() {
	sc.Split(bufio.ScanWords)
	n = nextInt()

	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			A[i][j] = T
		}
	}
	for i := 0; i < n; i++ {
		u := nextInt()
		k := nextInt()
		for j := 0; j < k; j++ {
			v := nextInt()
			c := nextInt()
			A[u][v] = c
		}
	}
	Shortestsearch()
}

C++: #include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <bitset>
#include <utility>
#include <functional>
#include <numeric>

//TODO

template <class T>
using vec = std::vector<T>;

constexpr int nil = -1;
constexpr int inf = 1 << 30;

struct Edge
{
    int to;
    int cost;
};

vec<int> dijkstra(const vec<vec<Edge>>& edges)
{
    using namespace std;

    const int n = edges.size();
    vec<int> distances(n, inf);
    vec<bool> reached(n, false);

    distances[0] = 0;

    while (true)
    {
        int minCost {inf};
        int u {};

        for (int i = 0; i < n; ++i)
        {
            if (!reached[i] && distances[i] < minCost)
            {
                minCost = distances[i];
                u = i;
            }
        }

        if (minCost == inf)
            break;
        
        reached[u] = true;

        for (auto& e : edges[u])
        {
            distances[e.to] = min(distances[e.to], distances[u] + e.cost);
        }
    }

    return distances;
}

void solve()
{
    using namespace std;
    int n;
    cin >> n;

    //隣接リスト形式
    vec<vec<Edge>> edges(n);
    
    //入力
    for (int i = 0, k; i < n; ++i)
    {
        cin.ignore();
        cin.ignore();
        cin >> k;
        for (int j = 0, to, cost; j < k; ++j)
        {
            cin >> to >> cost;
            edges[i].push_back({to, cost});
        }
    }

    auto d = dijkstra(edges);

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

int main()
{
    solve();
    return 0;
}

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