/*
If you want to aim high, aim high
Don't let that studying and grades consume you
Just live life young
******************************
What do you think? What do you think?
1st on Billboard, what do you think of it
Next is a Grammy, what do you think of it
However you think, I’m sorry, but shit, I have no fcking interest
*******************************
I'm standing on top of my Monopoly board
That means I'm on top of my game and it don't stop
til my hip don't hop anymore
https://www.a2oj.com/Ladder16.html
*******************************
300iq as writer = Sad!
*/
import java.util.*;
import java.io.*;
import java.math.*;

   public class x1242C2
   {
      public static void main(String hi[]) throws Exception
      {
         BufferedReader infile = new BufferedReader(new InputStreamReader(System.in));
         StringTokenizer st = new StringTokenizer(infile.readLine());
         int N = Integer.parseInt(st.nextToken());
         long[] sums = new long[N];
         ArrayList<Integer>[] boxes = new ArrayList[N];
         for(int i=0; i < N; i++)
         {
            boxes[i] = new ArrayList<Integer>();
            st = new StringTokenizer(infile.readLine());
            int a = Integer.parseInt(st.nextToken());
            while(a-->0)
               boxes[i].add(Integer.parseInt(st.nextToken()));
            for(int x: boxes[i])
               sums[i] += x;
         }
         long lmaosum = 0L;
         for(long x: sums)
            lmaosum += x;
         if(Math.abs(lmaosum)%N != 0)
         {
            System.out.println("No");
            return;
         }
         long target = lmaosum/N;
         //fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck
         HashMap<Long, Integer> map = new HashMap<Long, Integer>();
         for(int k=0; k < N; k++)
            for(int x: boxes[k])
               map.put((long)x, k);
         HashMap<Long, Long> edges = new HashMap<Long, Long>();
         for(int k=0; k < N; k++)
            for(int x: boxes[k])
            {
               long nextval = target-sums[k]+x;
               if(map.containsKey(nextval))
                  edges.put((long)x, nextval);
            }
         Node[] dp = new Node[1<<N];
         dp[0] = new Node(-69, -69, 0);
         //precompute subsets ass
         Node[] subsets = new Node[1<<N];
         for(int b=0; b < N; b++)
            for(int i=0; i < boxes[b].size(); i++)
            {
               if(!edges.containsKey((long)boxes[b].get(i)))
                  continue;
               long curr = edges.get((long)boxes[b].get(i));
               //shit shit shit shit shit shit shit shit shit shit
               int submask = 0;  boolean cyclic = true;
               while(curr != boxes[b].get(i))
               {
                  int k = map.get(curr);
                  if((submask&(1<<k)) > 0 || !edges.containsKey((long)curr))
                  {
                     cyclic = false;
                     break;
                  }
                  submask |= 1<<k;
                  curr = edges.get((long)curr);
               }
               submask |= (1<<b);
               if(cyclic)
                  subsets[submask] = new Node(-69, i, b);
            }
         for(int mask=1; mask < (1<<N); mask++)
            outer:for(int submask=mask; submask > 0; submask=(submask-1)&mask)
               if(dp[mask^submask] != null && subsets[submask] != null)
               {
                  dp[mask] = new Node(mask^submask, subsets[submask].dex, subsets[submask].start);
                  break outer;
               }
         if(dp[(1<<N)-1] == null)
            System.out.println("No");
         else
         {
            StringBuilder sb = new StringBuilder("Yes\n");
            long[][] res = new long[N][2];
            for(int i=0; i < N; i++)
               res[i][1] = -1L;
            int currmask = (1<<N)-1;
            while(currmask != 0)
            {
               int submask = dp[currmask].mask;
               int i = dp[currmask].dex;
               int b = dp[currmask].start;
               long nextval = target-sums[b]+boxes[b].get(i);
               int curr = map.get(nextval);
               res[map.get(nextval)][0] = nextval;
               res[map.get(nextval)][1] = b;
               while(true) //lol
               {
                  int lol = map.get(nextval);
                  nextval = edges.get(nextval);
                  res[map.get(nextval)][0] = nextval;
                  if(res[map.get(nextval)][1] != -1)
                     break;
                  res[map.get(nextval)][1] = lol;
               }
               currmask = dp[currmask].mask;
            }
            for(int k=0; k < N; k++)
               sb.append(res[k][0]+" ").append(res[k][1]+1).append("\n");
            System.out.print(sb);
         }
      }
   }
   class Node
   {
      public int mask;
      public int dex;
      public int start;

      public Node(int a, int b, int c)
      {
         mask = a;
         dex = b;
         start = c;
      }
   }


import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeSet;

public final class CF_599_D1_C
{

	static boolean verb=true;
	static void log(Object X){if (verb) System.err.println(X);}
	static void log(Object[] X){if (verb) {for (Object U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X){if (verb) {for (int U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X,int L){if (verb) {for (int i=0;i<L;i++) System.err.print(X[i]+" ");System.err.println("");}}
	static void log(long[] X){if (verb) {for (long U:X) System.err.print(U+" ");System.err.println("");}}

	static void logWln(Object X){if (verb) System.err.print(X);}
	static void info(Object o){	System.out.println(o);}
	static void output(Object o){outputWln(""+o+"\n");	}
	static void outputWln(Object o){try {out.write(""+ o);} catch (Exception e) {}}

	static long mod=1000000007;

	// Global vars
	static BufferedWriter out;
	static InputReader reader;

	static class Composite implements Comparable<Composite>{
		int idx;
		int v;

		public int compareTo(Composite X) {
			if (v!=X.v)
				return v-X.v;
			return idx-X.idx;

		}

		public Composite(int idx, int v) {
			this.idx = idx;
			this.v = v;
		}

	}

	static void test() {
		log("testing");

		log("done");

	}

	static void explore(ArrayList<Integer>[] components,ArrayList<Integer> bob,int[][] move,ArrayList<int[]>[] howto,int[][] list) {

		for (int x:bob) {
			if (components[x].size()==1) {
				int tm[]=howto[x].get(0);

				int L=howto[x].size();
				howto[x].add(tm);
				for (int i=0;i<L;i++) {
					int[] cur=howto[x].get(i);
					int[] nx=howto[x].get(i+1);
					int a=cur[0];
					int a2=nx[0];
					int b2=nx[1];
					move[a2][0]=list[a2][b2];
					move[a2][1]=a;
				}

			} else {
				explore(components,components[x],move,howto,list);
			}
		}
	}

	static void process() throws Exception {

		//arrayTest();

		out = new BufferedWriter(new OutputStreamWriter(System.out));
		reader = new InputReader(System.in);

		int k=reader.readInt();
		int[][] list=new int[k][];
		long[] sum=new long[k];
		int[] L=new int[k];
		HashMap<Integer,int[]> target=new HashMap<Integer,int[]>();
		long tot=0;
		for (int i=0;i<k;i++) {
			L[i]=reader.readInt();
			list[i]=new int[L[i]];
			for (int j=0;j<L[i];j++) {
				list[i][j]=reader.readInt();
				sum[i]+=list[i][j];
				target.put(list[i][j],new int[] {i,j});
			}
			tot+=sum[i];
		}

		int MX=1<<k;
		int AX=1000000001;
		ArrayList<int[]>[] howto=new ArrayList[MX];

		log("ok with the data");

		if (tot%k!=0) {
			output("No");
		} else {

			tot/=k;

			for (int i=0;i<k;i++) {

				if (sum[i]==tot) {
					//log("nothing to do for i:"+i);
					// nothing to do
					int mask=1<<i;
					ArrayList<int[]> cand=new ArrayList<int[]>();
					cand.add(new int[] {i,0});
					howto[mask]=cand;
				} else

					for (int j=0;j<L[i];j++) {
						int u=i;
						int v=j;
						boolean ok=true;
						int src_u=u;
						int src_v=v;
						int mask=0;
						boolean goon=true;
						ArrayList<int[]> cand=new ArrayList<int[]>();
						//log("start loop");
						while (goon) {
							cand.add(new int[] {u,v});
							//log("u:"+u+" v:"+v);
							ok=false;
							goon=false;
							long need=tot-((long)sum[u]-(long)list[u][v]);
							if (Math.abs(need)<=AX) {
								//log("need:"+need);
								int nd=(int)need;
								int[] tm=target.get(nd);
								//log("tm:"+tm);
								if (tm!=null) {
									//log("can find successor");
									int nxu=tm[0];
									int nxv=tm[1];
									if ((mask&(1<<nxu))==0) {
										mask|=1<<nxu;
										if (nxu==src_u) {
											// looping back to source
											if (nxv==src_v)
												ok=true;
										} else {
											u=nxu;
											v=nxv;
											ok=true;
											goon=true;
										}
									}
								}
							}
						}
						if (ok) {
							if (howto[mask]==null) {

								howto[mask]=cand;

							}
						}
					}
			}

			log("step 1 done");

			// now mask

			ArrayList[] components=new ArrayList[MX];

			for (int m=0;m<MX;m++) {
				if (howto[m]!=null) {
					//String s=Integer.toBinaryString(m);
					//while (s.length()<k)
					//	s="0"+s;
					//log("found mask:"+s);
					components[m]=new ArrayList<Integer>();
					components[m].add(m);
				}
			}

			int[] msk=new int[MX];
			int w=0;

			for (int a=0;a<MX;a++) {
				if (howto[a]!=null) {
					ArrayList<Integer> add=new ArrayList<Integer>();

					int ww=w;
					for (int i=0;i<ww;i++) {
						int b=msk[i];
						if ((b&a)==0) {

							int c=b|a;
							log("creating c:"+c+" ");
							if (components[c]==null ) {
								components[c]=new ArrayList<Integer>();
								components[c].add(a);
								components[c].add(b);
								msk[w++]=c;
							}
						}
					}
					msk[w++]=a;
				}
			}
			//log("msk:"+msk);
			//log(components[MX-1]);
			if (components[MX-1]!=null) {
				output("Yes");
				int[][] move=new int[k][2];
				explore(components,components[MX-1],move,howto,list);
				for (int i=0;i<k;i++) {
					output(move[i][0]+" "+(move[i][1]+1));
				}

			} else {
				output("No");
			}

		}

		try {
			out.close();
		} catch (Exception e) {
		}

	}

	public static void main(String[] args) throws Exception {
		process();

	}

	static final class InputReader {
		private final InputStream stream;
		private final byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		private int read() throws IOException {
			if (curChar >= numChars) {
				curChar = 0;
				numChars = stream.read(buf);
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public final String readString() throws IOException {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			StringBuilder res = new StringBuilder();
			do {
				res.append((char) c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public final int readInt() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			int res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		public final long readLong() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			long res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		private boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}
	}

}


/*
If you want to aim high, aim high
Don't let that studying and grades consume you
Just live life young
******************************
What do you think? What do you think?
1st on Billboard, what do you think of it
Next is a Grammy, what do you think of it
However you think, I’m sorry, but shit, I have no fcking interest
*******************************
I'm standing on top of my Monopoly board
That means I'm on top of my game and it don't stop
til my hip don't hop anymore
https://www.a2oj.com/Ladder16.html
*******************************
300iq as writer = Sad!
*/
import java.util.*;
import java.io.*;
import java.math.*;

   public class x1242C2
   {
      public static void main(String hi[]) throws Exception
      {
         BufferedReader infile = new BufferedReader(new InputStreamReader(System.in));
         StringTokenizer st = new StringTokenizer(infile.readLine());
         int N = Integer.parseInt(st.nextToken());
         long[] sums = new long[N];
         ArrayList<Integer>[] boxes = new ArrayList[N];
         for(int i=0; i < N; i++)
         {
            boxes[i] = new ArrayList<Integer>();
            st = new StringTokenizer(infile.readLine());
            int a = Integer.parseInt(st.nextToken());
            while(a-->0)
               boxes[i].add(Integer.parseInt(st.nextToken()));
            for(int x: boxes[i])
               sums[i] += x;
         }
         long lmaosum = 0L;
         for(long x: sums)
            lmaosum += x;
         if(Math.abs(lmaosum)%N != 0)
         {
            System.out.println("No");
            return;
         }
         long target = lmaosum/N;
         //fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck fuck
         HashMap<Long, Integer> map = new HashMap<Long, Integer>();
         for(int k=0; k < N; k++)
            for(int x: boxes[k])
               map.put((long)x, k);
         HashMap<Long, Long> edges = new HashMap<Long, Long>();
         for(int k=0; k < N; k++)
            for(int x: boxes[k])
            {
               long nextval = target-sums[k]+x;
               if(map.containsKey(nextval))
                  edges.put((long)x, nextval);
            }
         Node[] dp = new Node[1<<N];
         dp[0] = new Node(-69, -69, 0);
         //precompute subsets ass
         Node[] subsets = new Node[1<<N];
         for(int b=0; b < N; b++)
            for(int i=0; i < boxes[b].size(); i++)
            {
               if(!edges.containsKey((long)boxes[b].get(i)))
                  continue;
               long curr = edges.get((long)boxes[b].get(i));
               //shit shit shit shit shit shit shit shit shit shit
               int submask = 0;  boolean cyclic = true;
               while(curr != boxes[b].get(i))
               {
                  int k = map.get(curr);
                  if((submask&(1<<k)) > 0 || !edges.containsKey((long)curr))
                  {
                     cyclic = false;
                     break;
                  }
                  submask |= 1<<k;
                  curr = edges.get((long)curr);
               }
               submask |= (1<<b);
               if(cyclic)
                  subsets[submask] = new Node(-69, i, b);
            }
         for(int mask=1; mask < (1<<N); mask++)
            outer:for(int submask=mask; submask > 0; submask=(submask-1)&mask)
               if(dp[mask^submask] != null && subsets[submask] != null)
               {
                  dp[mask] = new Node(mask^submask, subsets[submask].dex, subsets[submask].start);
                  break outer;
               }
         if(dp[(1<<N)-1] == null)
            System.out.println("No");
         else
         {
            StringBuilder sb = new StringBuilder("Yes\n");
            long[][] res = new long[N][2];
            for(int i=0; i < N; i++)
               res[i][1] = -1L;
            int currmask = (1<<N)-1;
            while(currmask != 0)
            {
               int submask = dp[currmask].mask;
               int i = dp[currmask].dex;
               int b = dp[currmask].start;
               long nextval = target-sums[b]+boxes[b].get(i);
               int curr = map.get(nextval);
               res[map.get(nextval)][0] = nextval;
               res[map.get(nextval)][1] = b;
               while(true)
               {
                  int lol = map.get(nextval);
                  nextval = edges.get(nextval);
                  res[map.get(nextval)][0] = nextval;
                  if(res[map.get(nextval)][1] != -1)
                     break;
                  res[map.get(nextval)][1] = lol;
               }
               currmask = dp[currmask].mask;
            }
            for(int k=0; k < N; k++)
               sb.append(res[k][0]+" ").append(res[k][1]+1).append("\n");
            System.out.print(sb);
         }
      }
   }
   class Node
   {
      public int mask;
      public int dex;
      public int start;

      public Node(int a, int b, int c)
      {
         mask = a;
         dex = b;
         start = c;
      }
   }


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;

public class C {

	public static void main(String[] args) {
		FastScanner fs=new FastScanner();
		int nBoxes=fs.nextInt();
		long[] sums=new long[nBoxes];
		HashMap<Long, Integer> boxOf=new HashMap<>();
		int[][] boxes=new int[nBoxes][];
		long total=0;
		for (int i=0; i<nBoxes; i++) {
			int size=fs.nextInt();
			boxes[i]=new int[size];
			for (int j=0; j<size; j++) {
				boxes[i][j]=fs.nextInt();
				boxOf.put((long)boxes[i][j], i);
				sums[i]+=boxes[i][j];
			}
			total+=sums[i];
		}
		if (total%nBoxes!=0) {
			System.out.println("No");
			return;
		}

		long target=total/nBoxes;
		int[][] masks=new int[nBoxes][];
		ArrayList<Integer>[][] maskLoops=new ArrayList[nBoxes][];
		for (int i=0; i<nBoxes; i++) {
			masks[i]=new int[boxes[i].length];
			maskLoops[i]=new ArrayList[boxes[i].length];
			for (int j=0; j<maskLoops[i].length; j++) maskLoops[i][j]=new ArrayList<>();

			inner:for (int j=0; j<boxes[i].length; j++) {
				long startVal=boxes[i][j], lookingFor=target-(sums[i]-startVal);
				maskLoops[i][j].add((int)lookingFor);
				int mask=1<<i;
				while (lookingFor!=startVal) {
					if (!boxOf.containsKey(lookingFor)) continue inner;
					int nextBox=boxOf.get(lookingFor);

					//if we have already used this box, it won't work
					if ((mask&(1<<nextBox))!=0) continue inner;

					mask|=1<<nextBox;
					lookingFor=target-(sums[nextBox]-lookingFor);
					/*if (lookingFor!=startVal) */maskLoops[i][j].add((int)lookingFor);
				}
//				System.out.println("Mask loops for box: "+i+" starting at "+startVal+" gives "+);

				//otherwise it worked
				masks[i][j]=mask;
			}
		}

		boolean[] possible=new boolean[1<<nBoxes];
		int[] maskFrom=new int[1<<nBoxes];
		int[] indexToUse=new int[1<<nBoxes];
		possible[0]=true;
		for (int mask=1; mask<1<<nBoxes; mask++) {
			int lowestBit=Integer.numberOfTrailingZeros(Integer.lowestOneBit(mask));
			/*
			for (int i:masks[lowestBit]) {
				if ((mask&i)==i && possible[mask^i]) {
					possible[mask]=true;
					break;
				}
			}
			*/

			for (int i=0; i<masks[lowestBit].length; i++) {
				int m=masks[lowestBit][i];
				if ((mask&m)==m && possible[mask^m]) {
					possible[mask]=true;
					maskFrom[mask]=mask^m;
					indexToUse[mask]=i;
					break;
				}
			}
		}
		if (!possible[(1<<nBoxes)-1]) {
			System.out.println("No");
			return;
		}
		System.out.println("Yes");
		ArrayList<ArrayList<Integer>> loops=new ArrayList<>();
		int mask=(1<<nBoxes)-1;
		while (mask!=0) {
//			System.out.println("At mask: "+Integer.toBinaryString(mask));
			int lowestBit=Integer.numberOfTrailingZeros(Integer.lowestOneBit(mask));
			loops.add(maskLoops[lowestBit][indexToUse[mask]]);
			mask=maskFrom[mask];
		}

//		System.out.println("Loops: "+loops);

		int[] takeFrom=new int[nBoxes];
		int[] boxGiveTo=new int[nBoxes];
		for (ArrayList<Integer> loop:loops) {
			for (int i=0; i<loop.size(); i++) {
				int cur=loop.get(i), next=loop.get((i+1)%loop.size());
				int curBox=boxOf.get((long)cur), nextBox=boxOf.get((long)next);
				takeFrom[nextBox]=next;
				boxGiveTo[nextBox]=curBox;
			}
		}
		for (int i=0; i<nBoxes; i++) {
			System.out.println(takeFrom[i]+" "+(boxGiveTo[i]+1));
		}
	}

	static class FastScanner {
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st=new StringTokenizer("");
		public String next() {
			while (!st.hasMoreElements())
				try {
					st=new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			return st.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}
	}

}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Map;
import java.io.BufferedReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastScanner in = new FastScanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC {
        int n;
        int[] bitCount;
        long neededSum;
        long[] sums;
        Map<Long, Integer> where;

        public void solve(int testNumber, FastScanner in, PrintWriter out) {
            n = in.nextInt();
            int[][] a = new int[n][];
            neededSum = 0;
            sums = new long[n];
            for (int i = 0; i < n; i++) {
                int k = in.nextInt();
                a[i] = new int[k];
                for (int j = 0; j < k; j++) {
                    a[i][j] = in.nextInt();
                    neededSum += a[i][j];
                    sums[i] += a[i][j];
                }
            }

            if (neededSum % n != 0) {
                out.println("No");
                return;
            }
            neededSum /= n;

            where = new HashMap<>();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < a[i].length; j++) {
                    where.put((long) a[i][j], i);
                }
            }
            bitCount = new int[1 << n];
            for (int i = 0; i < bitCount.length; i++) {
                bitCount[i] = Integer.bitCount(i);
            }

            Entry[][] cycleSol = new Entry[1 << n][];

            List<Entry> sol = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                for (int x : a[i]) {
                    search(i, i, x, x, 0, 0, sol, cycleSol);
                }
            }

            boolean[] can = new boolean[1 << n];
            int[] via = new int[1 << n];
            can[0] = true;
            for (int mask = 0; mask < 1 << n; mask++) {
                for (int submask = mask; submask > 0; submask = (submask - 1) & mask) {
                    if (cycleSol[submask] != null && can[mask ^ submask]) {
                        can[mask] = true;
                        via[mask] = submask;
                    }
                }
            }

            if (!can[(1 << n) - 1]) {
                out.println("No");
                return;
            }

            int[][] ans = new int[n][2];
            for (int mask = (1 << n) - 1; mask > 0; ) {
                int sm = via[mask];
                mask ^= sm;

                for (Entry e : cycleSol[sm]) {
                    ans[e.from][0] = e.what;
                    ans[e.from][1] = e.to + 1;
                }
            }

            out.println("Yes");
            for (int i = 0; i < n; i++) {
                out.println(ans[i][0] + " " + ans[i][1]);
            }
        }

        private void search(int start, int cur, long fromStart, long fromCur, int hasIn, int hasOut, List<Entry> sol, Entry[][] cycleSol) {
            for (int i = start; i < n; i++) {
                if ((hasIn & (1 << i)) > 0) {
                    continue;
                }
                if ((hasOut & (1 << cur)) > 0) {
                    continue;
                }
                long fromI = sums[i] + fromCur - neededSum;
                Integer w = where.get(fromI);
                if (w == null || w != i) {
                    continue;
                }
                sol.add(new Entry(cur, i, (int) fromCur));
                int nHasIn = hasIn | (1 << i);
                int nHasOut = hasOut | (1 << cur);
                if (i == start && fromI == fromStart) {
                    cycleSol[nHasOut] = sol.toArray(new Entry[0]);
                }
                search(start, i, fromStart, fromI, nHasIn, nHasOut, sol, cycleSol);
                sol.remove(sol.size() - 1);
            }
        }

        class Entry {
            int from;
            int to;
            int what;

            Entry(int from, int to, int what) {
                this.from = from;
                this.to = to;
                this.what = what;
            }

            public String toString() {
                return from + " " + to + " " + what;
            }

        }

    }

    static class FastScanner {
        private BufferedReader in;
        private StringTokenizer st;

        public FastScanner(InputStream stream) {
            in = new BufferedReader(new InputStreamReader(stream));
        }

        public String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    String rl = in.readLine();
                    if (rl == null) {
                        return null;
                    }
                    st = new StringTokenizer(rl);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return st.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author beginner1010
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        HashMap<Integer, Integer> map = new HashMap<>();
        boolean[] dp;
        boolean[] vis;
        boxPair[] ans;

        int two(int bit) {
            return 1 << bit;
        }

        boolean contain(int mask, int bit) {
            return ((two(bit) & mask) > 0);
        }

        int get(long val) {
            if (val > Integer.MAX_VALUE || val < Integer.MIN_VALUE) return -1;
            int key = (int) val;
            if (map.containsKey(key) == false) return -1;
            return map.get(key);
        }

        boolean rec(int mask, boolean[] hasCycle) {
            if (hasCycle[mask]) return true;
            if (vis[mask] == true) return dp[mask];
            vis[mask] = true;
            for (int i = mask & (mask - 1); i > 0; i = mask & (i - 1)) {
                if (rec(i, hasCycle) && rec(i ^ mask, hasCycle)) {
                    return dp[mask] = true;
                }
            }
            return dp[mask] = false;
        }

        void findPath(int mask, boolean[] hasCycle, ArrayList<boxPair>[] maskPath) {
            if (hasCycle[mask]) {
                for (boxPair b : maskPath[mask]) {
                    ans[get(b.addTo)] = b;
                }
                return;
            }
            for (int i = mask & (mask - 1); i > 0; i = mask & (i - 1)) {
                if (rec(i, hasCycle) && rec(i ^ mask, hasCycle)) {
                    findPath(i, hasCycle, maskPath);
                    findPath(i ^ mask, hasCycle, maskPath);
                    return;
                }
            }
        }

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int k = in.nextInt();
            int[][] a = new int[k][];
            int[] n = new int[k];
            long[] sum = new long[k];

            long S = 0;
            for (int i = 0; i < k; i++) {
                n[i] = in.nextInt();
                a[i] = new int[n[i]];
                for (int j = 0; j < n[i]; j++) {
                    a[i][j] = in.nextInt();
                    sum[i] += a[i][j];
                    map.put(a[i][j], i);
                }
                S += sum[i];
            }
            if (S % k != 0) out.println("No");
            else {
                ArrayList<boxPair>[] maskPath = new ArrayList[two(k)];
                boolean[] hasCycle = new boolean[two(k)];
                for (int i = 0; i < two(k); i++) {
                    maskPath[i] = new ArrayList<>();
                }
                long balance = S / k;
                for (int i = 0; i < k; i++) {
                    for (int j = 0; j < n[i]; j++) {
                        long remove = a[i][j];
                        int curID = i;
                        int curMask = 0;
                        ArrayList<boxPair> curPath = new ArrayList<>();
                        while (true) {
                            curMask |= two(curID);
                            remove = (balance - (sum[curID] - remove));
                            int nxtID = get(remove);
                            curPath.add(new boxPair(curID, (int) remove));
                            if (nxtID == i && remove == a[i][j]) {
                                if (hasCycle[curMask] == false) {
                                    hasCycle[curMask] = true;
                                    maskPath[curMask] = curPath;
                                }
                                break;
                            }
                            if (nxtID == -1 || contain(curMask, nxtID)) break;
                            curID = nxtID;
                        }
                    }
                }
                vis = new boolean[two(k)];
                dp = new boolean[two(k)];
                if (rec(two(k) - 1, hasCycle) == false) out.println("No");
                else {
                    ans = new boxPair[k];
                    findPath(two(k) - 1, hasCycle, maskPath);
                    out.println("Yes");
                    for (int i = 0; i < k; i++) {
                        out.println(ans[i].addTo + " " + (ans[i].boxID + 1));
                    }
                }
            }
        }

        class boxPair {
            int boxID;
            int addTo;

            boxPair(int _boxID, int _addTo) {
                this.boxID = _boxID;
                this.addTo = _addTo;
            }

        }

    }

    static class InputReader {
        InputStream is;
        private byte[] inbuf = new byte[1024];
        private int lenbuf = 0;
        private int ptrbuf = 0;
        static final int[] ints = new int[128];

        public InputReader(InputStream is) {
            for (int i = '0'; i <= '9'; i++) ints[i] = i - '0';
            this.is = is;
        }

        public int readByte() {
            if (lenbuf == -1) throw new InputMismatchException();
            if (ptrbuf >= lenbuf) {
                ptrbuf = 0;
                try {
                    lenbuf = is.read(inbuf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (lenbuf <= 0) return -1;
            }
            return inbuf[ptrbuf++];
        }

        public int nextInt() {
            int num = 0, b;
            boolean minus = false;
            while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-')) ;
            if (b == '-') {
                minus = true;
                b = readByte();
            }

            while (true) {
                if (b >= '0' && b <= '9') {
                    num = (num << 3) + (num << 1) + ints[b];
                } else {
                    return minus ? -num : num;
                }
                b = readByte();
            }
        }

    }
}


import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeSet;

public final class CF_599_D1_C
{

	static boolean verb=true;
	static void log(Object X){if (verb) System.err.println(X);}
	static void log(Object[] X){if (verb) {for (Object U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X){if (verb) {for (int U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X,int L){if (verb) {for (int i=0;i<L;i++) System.err.print(X[i]+" ");System.err.println("");}}
	static void log(long[] X){if (verb) {for (long U:X) System.err.print(U+" ");System.err.println("");}}

	static void logWln(Object X){if (verb) System.err.print(X);}
	static void info(Object o){	System.out.println(o);}
	static void output(Object o){outputWln(""+o+"\n");	}
	static void outputWln(Object o){try {out.write(""+ o);} catch (Exception e) {}}

	static long mod=1000000007;

	// Global vars
	static BufferedWriter out;
	static InputReader reader;

	static class Composite implements Comparable<Composite>{
		int idx;
		int v;

		public int compareTo(Composite X) {
			if (v!=X.v)
				return v-X.v;
			return idx-X.idx;

		}

		public Composite(int idx, int v) {
			this.idx = idx;
			this.v = v;
		}

	}

	static void test() {
		log("testing");

		log("done");

	}

	static void explore(ArrayList<Integer>[] components,ArrayList<Integer> bob,int[][] move,ArrayList<int[]>[] howto,int[][] list) {

		for (int x:bob) {
			if (components[x].size()==1) {
				int tm[]=howto[x].get(0);

				int L=howto[x].size();
				howto[x].add(tm);
				for (int i=0;i<L;i++) {
					int[] cur=howto[x].get(i);
					int[] nx=howto[x].get(i+1);
					int a=cur[0];
					int a2=nx[0];
					int b2=nx[1];
					move[a2][0]=list[a2][b2];
					move[a2][1]=a;
				}

			} else {
				explore(components,components[x],move,howto,list);
			}
		}
	}

	static void process() throws Exception {

		//arrayTest();

		out = new BufferedWriter(new OutputStreamWriter(System.out));
		reader = new InputReader(System.in);

		int k=reader.readInt();
		int[][] list=new int[k][];
		long[] sum=new long[k];
		int[] L=new int[k];
		HashMap<Integer,int[]> target=new HashMap<Integer,int[]>();
		long tot=0;
		for (int i=0;i<k;i++) {
			L[i]=reader.readInt();
			list[i]=new int[L[i]];
			for (int j=0;j<L[i];j++) {
				list[i][j]=reader.readInt();
				sum[i]+=list[i][j];
				target.put(list[i][j],new int[] {i,j});
			}
			tot+=sum[i];
		}

		int MX=1<<k;
		int AX=1000000001;
		ArrayList<int[]>[] howto=new ArrayList[MX];

		log("ok with the data");

		if (tot%k!=0) {
			output("No");
		} else {

			tot/=k;

			for (int i=0;i<k;i++) {

				if (sum[i]==tot) {
					//log("nothing to do for i:"+i);
					// nothing to do
					int mask=1<<i;
					ArrayList<int[]> cand=new ArrayList<int[]>();
					cand.add(new int[] {i,0});
					howto[mask]=cand;
				} else

					for (int j=0;j<L[i];j++) {
						int u=i;
						int v=j;
						boolean ok=true;
						int src_u=u;
						int src_v=v;
						int mask=0;
						boolean goon=true;
						ArrayList<int[]> cand=new ArrayList<int[]>();
						//log("start loop");
						while (goon) {
							cand.add(new int[] {u,v});
							//log("u:"+u+" v:"+v);
							ok=false;
							goon=false;
							long need=tot-((long)sum[u]-(long)list[u][v]);
							if (Math.abs(need)<=AX) {
								//log("need:"+need);
								int nd=(int)need;
								int[] tm=target.get(nd);
								//log("tm:"+tm);
								if (tm!=null) {
									//log("can find successor");
									int nxu=tm[0];
									int nxv=tm[1];
									if ((mask&(1<<nxu))==0) {
										mask|=1<<nxu;
										if (nxu==src_u) {
											// looping back to source
											if (nxv==src_v)
												ok=true;
										} else {
											u=nxu;
											v=nxv;
											ok=true;
											goon=true;
										}
									}
								}
							}
						}
						if (ok) {
							if (howto[mask]==null) {

								howto[mask]=cand;

							}
						}
					}
			}

			log("step 1 done");

			// now mask

			ArrayList[] components=new ArrayList[MX];

			int[] msk=new int[MX];
			int w=0;

			for (int m=0;m<MX;m++) {
				if (howto[m]!=null) {
					//String s=Integer.toBinaryString(m);
					//while (s.length()<k)
					//	s="0"+s;
					//log("found mask:"+s);
					components[m]=new ArrayList<Integer>();
					components[m].add(m);
					msk[w++]=m;
				}
			}

			int base=w;

			for (int e=0;e<base;e++) {
				int a=msk[e];
				int ww=w;
				for (int i=0;i<ww;i++) {
					int b=msk[i];
					if ((b&a)==0) {
						int c=b|a;
						//log("creating c:"+c+" ");
						if (components[c]==null ) {
							components[c]=new ArrayList<Integer>();
							components[c].add(a);
							components[c].add(b);
							msk[w++]=c;
						}
					}
				}
			}
			//log("msk:"+msk);
			//log(components[MX-1]);
			if (components[MX-1]!=null) {
				output("Yes");
				int[][] move=new int[k][2];
				explore(components,components[MX-1],move,howto,list);
				for (int i=0;i<k;i++) {
					output(move[i][0]+" "+(move[i][1]+1));
				}

			} else {
				output("No");
			}

		}

		try {
			out.close();
		} catch (Exception e) {
		}

	}

	public static void main(String[] args) throws Exception {
		process();

	}

	static final class InputReader {
		private final InputStream stream;
		private final byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		private int read() throws IOException {
			if (curChar >= numChars) {
				curChar = 0;
				numChars = stream.read(buf);
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public final String readString() throws IOException {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			StringBuilder res = new StringBuilder();
			do {
				res.append((char) c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public final int readInt() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			int res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		public final long readLong() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			long res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		private boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}
	}

}


import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TreeSet;

public final class CF_599_D1_C
{

	static boolean verb=true;
	static void log(Object X){if (verb) System.err.println(X);}
	static void log(Object[] X){if (verb) {for (Object U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X){if (verb) {for (int U:X) System.err.print(U+" ");System.err.println("");}}
	static void log(int[] X,int L){if (verb) {for (int i=0;i<L;i++) System.err.print(X[i]+" ");System.err.println("");}}
	static void log(long[] X){if (verb) {for (long U:X) System.err.print(U+" ");System.err.println("");}}

	static void logWln(Object X){if (verb) System.err.print(X);}
	static void info(Object o){	System.out.println(o);}
	static void output(Object o){outputWln(""+o+"\n");	}
	static void outputWln(Object o){try {out.write(""+ o);} catch (Exception e) {}}

	static long mod=1000000007;

	// Global vars
	static BufferedWriter out;
	static InputReader reader;

	static class Composite implements Comparable<Composite>{
		int idx;
		int v;

		public int compareTo(Composite X) {
			if (v!=X.v)
				return v-X.v;
			return idx-X.idx;

		}

		public Composite(int idx, int v) {
			this.idx = idx;
			this.v = v;
		}

	}

	static void test() {
		log("testing");

		log("done");

	}

	static void explore(ArrayList<Integer>[] components,ArrayList<Integer> bob,int[][] move,ArrayList<int[]>[] howto,int[][] list) {

		for (int x:bob) {
			if (components[x].size()==1) {
				int tm[]=howto[x].get(0);

				int L=howto[x].size();
				howto[x].add(tm);
				for (int i=0;i<L;i++) {
					int[] cur=howto[x].get(i);
					int[] nx=howto[x].get(i+1);
					int a=cur[0];
					int a2=nx[0];
					int b2=nx[1];
					move[a2][0]=list[a2][b2];
					move[a2][1]=a;
				}

			} else {
				explore(components,components[x],move,howto,list);
			}
		}
	}

	static void process() throws Exception {

		//arrayTest();

		out = new BufferedWriter(new OutputStreamWriter(System.out));
		reader = new InputReader(System.in);

		int k=reader.readInt();
		int[][] list=new int[k][];
		long[] sum=new long[k];
		int[] L=new int[k];
		HashMap<Integer,int[]> target=new HashMap<Integer,int[]>();
		long tot=0;
		for (int i=0;i<k;i++) {
			L[i]=reader.readInt();
			list[i]=new int[L[i]];
			for (int j=0;j<L[i];j++) {
				list[i][j]=reader.readInt();
				sum[i]+=list[i][j];
				target.put(list[i][j],new int[] {i,j});
			}
			tot+=sum[i];
		}

		int MX=1<<k;
		int AX=1000000001;
		ArrayList<int[]>[] howto=new ArrayList[MX];

		log("ok with the data");

		if (tot%k!=0) {
			output("No");
		} else {

			tot/=k;

			for (int i=0;i<k;i++) {

				if (sum[i]==tot) {
					//log("nothing to do for i:"+i);
					// nothing to do
					int mask=1<<i;
					ArrayList<int[]> cand=new ArrayList<int[]>();
					cand.add(new int[] {i,0});
					howto[mask]=cand;
				} else

					for (int j=0;j<L[i];j++) {
						int u=i;
						int v=j;
						boolean ok=true;
						int src_u=u;
						int src_v=v;
						int mask=0;
						boolean goon=true;
						ArrayList<int[]> cand=new ArrayList<int[]>();
						//log("start loop");
						while (goon) {
							cand.add(new int[] {u,v});
							//log("u:"+u+" v:"+v);
							ok=false;
							goon=false;
							long need=tot-((long)sum[u]-(long)list[u][v]);
							if (Math.abs(need)<=AX) {
								//log("need:"+need);
								int nd=(int)need;
								int[] tm=target.get(nd);
								//log("tm:"+tm);
								if (tm!=null) {
									//log("can find successor");
									int nxu=tm[0];
									int nxv=tm[1];
									if ((mask&(1<<nxu))==0) {
										mask|=1<<nxu;
										if (nxu==src_u) {
											// looping back to source
											if (nxv==src_v)
												ok=true;
										} else {
											u=nxu;
											v=nxv;
											ok=true;
											goon=true;
										}
									}
								}
							}
						}
						if (ok) {
							if (howto[mask]==null) {

								howto[mask]=cand;

							}
						}
					}
			}

			log("step 1 done");

			// now mask

			ArrayList<Integer> msk=new ArrayList<Integer>();
			ArrayList[] components=new ArrayList[MX];

			for (int m=0;m<MX;m++) {
				if (howto[m]!=null) {
					//String s=Integer.toBinaryString(m);
					//while (s.length()<k)
					//	s="0"+s;
					//log("found mask:"+s);
					components[m]=new ArrayList<Integer>();
					components[m].add(m);
				}
			}

			int[] visited=new int[MX];

			for (int a=0;a<MX;a++) {
				if (howto[a]!=null) {
					ArrayList<Integer> add=new ArrayList<Integer>();

					for (int b:msk) {
						if ((b&a)==0) {

							int c=b|a;
							log("creating c:"+c+" ");
							if (components[c]==null) {
								components[c]=new ArrayList<Integer>();
								components[c].add(a);
								components[c].add(b);
								add.add(c);
							}
						}
					}
					msk.add(a);
					for (int c:add) {

							msk.add(c);

					}
				}
			}
			//log("msk:"+msk);
			//log(components[MX-1]);
			if (components[MX-1]!=null) {
				output("Yes");
				int[][] move=new int[k][2];
				explore(components,components[MX-1],move,howto,list);
				for (int i=0;i<k;i++) {
					output(move[i][0]+" "+(move[i][1]+1));
				}

			} else {
				output("No");
			}

		}

		try {
			out.close();
		} catch (Exception e) {
		}

	}

	public static void main(String[] args) throws Exception {
		process();

	}

	static final class InputReader {
		private final InputStream stream;
		private final byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;

		public InputReader(InputStream stream) {
			this.stream = stream;
		}

		private int read() throws IOException {
			if (curChar >= numChars) {
				curChar = 0;
				numChars = stream.read(buf);
				if (numChars <= 0) {
					return -1;
				}
			}
			return buf[curChar++];
		}

		public final String readString() throws IOException {
			int c = read();
			while (isSpaceChar(c)) {
				c = read();
			}
			StringBuilder res = new StringBuilder();
			do {
				res.append((char) c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public final int readInt() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			int res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		public final long readLong() throws IOException {
			int c = read();
			boolean neg = false;
			while (isSpaceChar(c)) {
				c = read();
			}
			char d = (char) c;
			// log("d:"+d);
			if (d == '-') {
				neg = true;
				c = read();
			}
			long res = 0;
			do {
				res *= 10;
				res += c - '0';
				c = read();
			} while (!isSpaceChar(c));
			// log("res:"+res);
			if (neg)
				return -res;
			return res;

		}

		private boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}
	}

}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.io.UncheckedIOException;
import java.util.Map;
import java.io.Closeable;
import java.util.Map.Entry;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 27);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            TaskC solver = new TaskC();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class TaskC {
        SubsetGenerator sg = new SubsetGenerator();
        Node[] nodes;
        int n;
        Map<Long, Node> map;
        long notExist;
        long[] mask2Key;
        Map<Long, LongList> sequence;
        DigitUtils.BitOperator bo = new DigitUtils.BitOperator();
        boolean[] dp;

        public void solve(int testNumber, FastInput in, FastOutput out) {
            n = in.readInt();
            nodes = new Node[n];
            for (int i = 0; i < n; i++) {
                nodes[i] = new Node();
                nodes[i].id = i;
            }

            map = new LinkedHashMap<>(200000);
            for (int i = 0; i < n; i++) {
                int k = in.readInt();
                for (int j = 0; j < k; j++) {
                    long x = in.readInt();
                    map.put(x, nodes[i]);
                    nodes[i].sum += x;
                }
            }

            long total = 0;
            for (Node node : nodes) {
                total += node.sum;
            }

            if (total % n != 0) {
                out.println("No");
                return;
            }
            long avg = total / n;

            notExist = (long) 1e18;
            mask2Key = new long[1 << n];
            Arrays.fill(mask2Key, notExist);
            sequence = new HashMap<>(200000);

            for (Map.Entry<Long, Node> kv : map.entrySet()) {
                for (Node node : nodes) {
                    node.handled = false;
                }

                long key = kv.getKey();

                Node node = kv.getValue();
                node.handled = true;
                int mask = bo.setBit(0, node.id, true);

                LongList list = new LongList(15);
                list.add(key);

                long req = avg - (node.sum - key);
                boolean valid = true;

                while (true) {
                    if (req == key) {
                        break;
                    }
                    Node next = map.get(req);
                    if (next == null || next.handled) {
                        valid = false;
                        break;
                    }
                    next.handled = true;
                    list.add(req);
                    req = avg - (next.sum - req);
                    mask = bo.setBit(mask, next.id, true);
                }

                if (!valid) {
                    continue;
                }

                mask2Key[mask] = key;
                sequence.put(key, list);
            }

            dp = new boolean[1 << n];
            for (int i = 0; i < (1 << n); i++) {
                dp[i] = mask2Key[i] != notExist;
                sg.setSet(i);
                while (!dp[i] && sg.hasNext()) {
                    int next = sg.next();
                    if (next == 0 || next == i) {
                        continue;
                    }
                    dp[i] = dp[i] || (dp[next] && dp[i - next]);
                }
            }

            if (!dp[(1 << n) - 1]) {
                out.println("No");
                return;
            }

            populate((1 << n) - 1);
            out.println("Yes");
            for (Node node : nodes) {
                out.append(node.out).append(' ').append(node.to + 1).append('\n');
            }
        }

        public void populate(int mask) {
            if (mask2Key[mask] != notExist) {
                LongList list = sequence.get(mask2Key[mask]);
                int m = list.size();
                for (int i = 0; i < m; i++) {
                    long v = list.get(i);
                    long last = list.get(DigitUtils.mod(i - 1, m));
                    Node which = map.get(v);
                    Node to = map.get(last);

                    which.out = v;
                    which.to = to.id;
                }
                return;
            }

            sg.setSet(mask);
            while (sg.hasNext()) {
                int next = sg.next();
                if (next == 0 || next == mask) {
                    continue;
                }
                if (dp[next] && dp[mask - next]) {
                    populate(next);
                    populate(mask - next);
                    return;
                }
            }
        }

    }

    static class LongList {
        private int size;
        private int cap;
        private long[] data;
        private static final long[] EMPTY = new long[0];

        public LongList(int cap) {
            this.cap = cap;
            if (cap == 0) {
                data = EMPTY;
            } else {
                data = new long[cap];
            }
        }

        public LongList(LongList list) {
            this.size = list.size;
            this.cap = list.cap;
            this.data = Arrays.copyOf(list.data, size);
        }

        public LongList() {
            this(0);
        }

        private void ensureSpace(int need) {
            int req = size + need;
            if (req > cap) {
                while (cap < req) {
                    cap = Math.max(cap + 10, 2 * cap);
                }
                data = Arrays.copyOf(data, cap);
            }
        }

        private void checkRange(int i) {
            if (i < 0 || i >= size) {
                throw new ArrayIndexOutOfBoundsException();
            }
        }

        public long get(int i) {
            checkRange(i);
            return data[i];
        }

        public void add(long x) {
            ensureSpace(1);
            data[size++] = x;
        }

        public int size() {
            return size;
        }

        public String toString() {
            return Arrays.toString(Arrays.copyOf(data, size));
        }

    }

    static class SubsetGenerator {
        private int[] meanings = new int[33];
        private int[] bits = new int[33];
        private int remain;
        private int next;

        public void setSet(int set) {
            int bitCount = 0;
            while (set != 0) {
                meanings[bitCount] = set & -set;
                bits[bitCount] = 0;
                set -= meanings[bitCount];
                bitCount++;
            }
            remain = 1 << bitCount;
            next = 0;
        }

        public boolean hasNext() {
            return remain > 0;
        }

        private void consume() {
            remain = remain - 1;
            int i;
            for (i = 0; bits[i] == 1; i++) {
                bits[i] = 0;
                next -= meanings[i];
            }
            bits[i] = 1;
            next += meanings[i];
        }

        public int next() {
            int returned = next;
            consume();
            return returned;
        }

    }

    static class Node {
        int id;
        long sum;
        boolean handled;
        long out;
        long to;

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

    }

    static class FastOutput implements AutoCloseable, Closeable {
        private StringBuilder cache = new StringBuilder(10 << 20);
        private final Writer os;

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(long c) {
            cache.append(c);
            return this;
        }

        public FastOutput println(String c) {
            cache.append(c).append('\n');
            return this;
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class DigitUtils {
        private static final long[] DIGIT_VALUES = new long[19];

        static {
            DIGIT_VALUES[0] = 1;
            for (int i = 1; i < 19; i++) {
                DIGIT_VALUES[i] = DIGIT_VALUES[i - 1] * 10;
            }
        }

        private DigitUtils() {
        }

        public static int mod(int x, int mod) {
            x %= mod;
            if (x < 0) {
                x += mod;
            }
            return x;
        }

        public static class BitOperator {
            public int setBit(int x, int i, boolean v) {
                if (v) {
                    x |= 1 << i;
                } else {
                    x &= ~(1 << i);
                }
                return x;
            }

        }

    }
}


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.StringTokenizer;

public class C {

	static int K;
	static int sz[];
	static long vs[][];
	static long curSum[];
	static HashMap<Long, Integer> valToBucket;
	static long sum;
	static int maskIfPick[][];
	static int dp[];

	static int pickId[];
	static int newBox[];
	public static void main(String[] args) {
		FS in = new FS();
		K = in.nextInt();
		sz = new int[K];
		valToBucket = new HashMap<Long, Integer>();
		vs = new long[K][];
		curSum = new long[K];
		sum = 0;
		for(int i = 0; i < K; i++) {
			sz[i] = in.nextInt();
			vs[i] = new long[sz[i]];
			for(int j = 0; j < sz[i]; j++) {
				long v = in.nextLong();
				sum += v;
				curSum[i] += v;
				vs[i][j] = v;
				valToBucket.put(v, i);
			}
		}

		if(sum % K != 0) {
			System.out.println("No");
			return;
		}

		sum /= K;
		maskIfPick = new int[K][];
		//go through if i pick each node
		for(int i = 0; i < K; i++) {
			maskIfPick[i] = new int[sz[i]];
			for(int j = 0; j < sz[i]; j++) {

				int mask = (1<<i);
				boolean works = false;
				long curLookfor = (sum - (curSum[i]-vs[i][j]));
				while(true) {
					if(!valToBucket.containsKey(curLookfor)) break;
					int nextBucket = valToBucket.get(curLookfor);
					if(nextBucket == i) {
						works = curLookfor == vs[i][j];
						break;
					}
					else if((mask & (1<<nextBucket)) > 0) break;
					else {
						mask |= (1<<nextBucket);
						curLookfor = (sum - (curSum[nextBucket]-curLookfor));
					}
				}
				if(works) maskIfPick[i][j] = mask;
			}
		}
//		System.out.println("S= "+sum);
		dp = new int[1<<K];
		Arrays.fill(dp, -1);
		int res = go(0);
		if(res == 0) {
			System.out.println("No");
		}
		else {
			System.out.println("Yes");
			pickId = new int[K];
			newBox = new int[K];
			Arrays.fill(pickId, -1);
			buildback(0);
			for(int i = 0; i < K; i++) {
				System.out.println(vs[i][pickId[i]]+" "+(newBox[i]+1));
			}
		}

	}

	static void pick(int i, int j) {
//		System.out.println(" Pick "+i+" "+j);
		if(pickId[i] != -1) return;
		pickId[i] = j;

		long curLookfor = (sum - (curSum[i]-vs[i][j]));
		int nextBucket = valToBucket.get(curLookfor);
		newBox[nextBucket] = i;
		for(int k = 0; k < sz[nextBucket]; k++) {
			if(vs[nextBucket][k] == curLookfor) pick(nextBucket, k);
		}
	}

	static int go(int mask) {
		if(mask+1 == (1<<K)) return 1; //got to end
		if(dp[mask] != -1) return dp[mask];
		//get first bit that's off
		int bit = -1;
		for(int i = 0; i < K; i++) {
			if((mask & (1<<i)) == 0) { bit = i; break;}
		}

		int res = 0;
		//loop through things to take for this bit
		for(int take = 0; take < sz[bit]; take++) {
			int newMask = maskIfPick[bit][take];
			if(newMask == 0 || (mask & newMask) > 0) continue;
			res = (res | go(mask | newMask));
		}

		return dp[mask] = res;
	}

	static void buildback(int mask) {
		if(mask+1 == (1<<K)) return; //got to end
		//get first bit that's off
		int bit = -1;
		for(int i = 0; i < K; i++) {
			if((mask & (1<<i)) == 0) { bit = i; break;}
		}

		int res = 0;
		//loop through things to take for this bit
		for(int take = 0; take < sz[bit]; take++) {
			int newMask = maskIfPick[bit][take];
			if(newMask == 0 || (mask & newMask) > 0) continue;
			res = (res | go(mask | newMask));
			if(res == 1) {
				pick(bit, take);
				buildback(mask | newMask);
				break;
			}
		}
	}

	static class FS{
		BufferedReader br;
		StringTokenizer st;
		public FS() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {
			while(st == null || !st.hasMoreElements()) {
				try {st = new StringTokenizer(br.readLine());}
				catch(Exception e) { throw null;}
			}
			return st.nextToken();
		}
		int nextInt() { return Integer.parseInt(next());}
		double nextDouble() { return Double.parseDouble(next());}
		long nextLong() { return Long.parseLong(next());}
	}

}


import java.lang.*;
import java.util.*;
import java.io.*;

public class Main {
    void solve() {
        int m=ni();
        long a[][]=new long[m][];
        HashMap<Long,Integer> mp=new HashMap<>();
        long TS=0;
        long sm[]=new long[m];
        for(int i=0;i<m;i++){
            int sz=ni();
            a[i]=new long[sz];
            for(int j=0;j<sz;j++){
                a[i][j]=nl();
                mp.put(a[i][j],i);
                sm[i]+=a[i][j];
            }
            TS+=sm[i];
        }
        if(TS%m!=0){
            pw.println("No");
            return;
        }
        TS/=m;
        ArrayList<Node> ansForMask[]=new ArrayList[(1<<m)];
        for(int i=0;i<(1<<m);i++) ansForMask[i]=new ArrayList<>();
        ArrayList<Node> tempList=new ArrayList<>();
        int vis[]=new int[m];
        for(int i=0;i<m;i++){
            out:for(int j=0;j<a[i].length;j++){
                int mask=0;
                tempList.clear();
                long val=a[i][j],req=Long.MAX_VALUE;
                int idx=i,idx2;
                Arrays.fill(vis,0);
                if(sm[i]==TS){
                    mask=1<<i;
                    if(ansForMask[mask].size()==0) ansForMask[mask].add(new Node(val,i,i));
                    continue;
                }
                while(vis[idx]==0){
                    req=TS-(sm[idx]-val);
                    if(!mp.containsKey(req)) continue out;
                    idx2=mp.get(req);
                    if(vis[idx]==1 || idx==idx2) continue out;
                    if(vis[idx2]==1) break;
                //   if(i==0 && j==1) pw.println(idx2+" "+req+" "+val);
                    vis[idx]=1;
                    mask+=(1<<idx);
                    tempList.add(new Node(req,idx2,idx));
                    idx=idx2;
                    val=req;

                }
                if(req!=a[i][j])continue out;
                mask+=(1<<idx);
                tempList.add(new Node(a[i][j],i,idx));
                if(ansForMask[mask].size()==0){
                  // pw.println(Integer.toBinaryString(mask));
                    ansForMask[mask].addAll(tempList);
                }
            }
        }
        int dp[]=new int[1<<m];
        dp[0]=1;
       out: for(int mask=1;mask <(1<<m);mask++){
            if(ansForMask[mask].size()!=0){
                dp[mask]=1;
               // pw.println(Integer.toBinaryString(mask)+" "+mask);
                continue;
            }
            for(int s=mask;s>0;s=(s-1)&mask){
                if(dp[s]==1 && dp[mask^s]==1){
                    dp[mask]=1;
                    ansForMask[mask].addAll(ansForMask[s]);
                    ansForMask[mask].addAll(ansForMask[mask^s]);
                    continue out;

                }
            }
        }
        if(dp[(1<<m)-1]==0){
           pw.println("No");
           return;
        }
        pw.println("Yes");
        Pair ans[]=new Pair[m];
        for(Node p : ansForMask[(1<<m)-1]){
            ans[p.id1]=new Pair(p.c,p.id2);
        }
        for(int i=0;i<m;i++) pw.println(ans[i].c+" "+(ans[i].p+1));

    }
    class Pair {
        long c;
        int p;
        public Pair(long c,int p){
            this.c=c;
            this.p=p;
        }
    }
    class Node{
        long c;
        int id1;
        int id2;
        public Node(long c,int id1,int id2){
            this.c=c;
            this.id1=id1;
            this.id2=id2;
        }
    }
    long M = (long)1e9+7;
    // END
    PrintWriter pw;
    StringTokenizer st;
    BufferedReader br;

    void run() throws Exception {
        br = new BufferedReader(new InputStreamReader(System.in));
        pw = new PrintWriter(System.out);
        long s = System.currentTimeMillis();
        solve();
        pw.flush();
    }
    public static void main(String[] args) throws Exception {
        new Main().run();
    }

    String ns() {
        while (st == null || !st.hasMoreElements()) {

            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }

    String nextLine() throws Exception {
        String str = "";
        try {
            str = br.readLine();
        } catch (IOException e) {
            throw new Exception(e.toString());
        }
        return str;
    }

    int ni() {
        return Integer.parseInt(ns());
    }

    long nl() {
        return Long.parseLong(ns());
    }

    double nd() {
        return Double.parseDouble(ns());
    }
}


import java.util.*;
import java.io.*;

public class C599 {
    static ArrayList<Integer> [] adj;
    static long [] a; static int [] type;
    static Map<Long, Integer> map;
    static int [] vis;
    static HashSet<Integer> cy;
    static boolean [] good;
    static int [] dp;
    static HashSet<Integer> [] nodes;
    public static void main(String[] args) {
        MyScanner sc = new MyScanner();
        PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
        int k = sc.nextInt();
        int cur = 0;
        a = new long[75007]; long sum = 0;
        type = new int[75007];
        map = new HashMap<>();
        long [] typeSum = new long[k];
        for (int i = 0; i < k; i++) {
            int n = sc.nextInt(); long temp = sum;
            for (int j = 0; j < n; j++) {
                cur++;
                a[cur] = sc.nextLong();
                type[cur] = i;
                map.put(a[cur], cur);
                sum += a[cur];
            }
            typeSum[i] = sum - temp;
        }
        boolean notDiv = sum % k != 0;
        long need = sum / k;
        int n = cur;
        adj = new ArrayList[n + 1];
        for (int i = 1; i <= n; i++) adj[i] = new ArrayList<>();
        for (int i = 1; i <= n; i++) {
            long delta = need - typeSum[type[i]];
            long find = a[i] + delta;
            if (map.containsKey(find)) {
                if (type[map.get(find)] != type[i] || delta == 0) adj[i].add(map.get(find));
            }
        }
        vis = new int[n + 1];
        good = new boolean[1 << k];
        good[0] = true;
        nodes = new HashSet[1 << k];
        for (int i = 1; i <= n; i++) {
            if (vis[i] == 0) {
                cy = new HashSet<>();
                boolean b = dfs(i);
                int mask = 0;
                for (Integer node: cy) {
                    mask |= (1 << type[node]);
                }
                if (mask != 0) nodes[mask] = cy;
                good[mask] = true;
            }
        }
        dp = new int[1 << k];
        Arrays.fill(dp, -1);
        int possible = solve((1 << k) - 1);
        if (possible == 1 && !notDiv) {
            ArrayList<Integer> masks = dfs2((1 << k) - 1);

            long [] num = new long[k];
            int [] ret = new int[k];
            for (Integer mask: masks) {
                for (Integer node: nodes[mask]) {
                    num[type[node]] = a[node];
                    ret[type[adj[node].get(0)]] = type[node] + 1;
                }
            }
            boolean good = true; Set<Integer> soFar = new HashSet<>();
            for (int i = 0; i < ret.length; i++) {
                if (soFar.contains(ret[i])) good = false;
                soFar.add(ret[i]);
            }
            if (!good) {
                out.println("No");
                out.close();
                return;
            }
            out.println("Yes");
            for (int i = 0; i < k; i++) {
                out.println(num[i] + " " + ret[i]);
            }
        } else {
            out.println("No");
        }
        out.close();
    }

    static int solve(int mask) {
        if (dp[mask] != -1) return dp[mask];
        if (good[mask]) return dp[mask] = 1;
        int ret = 0;
        for (int i = (mask - 1) & mask; i > 0; i = (i - 1) & mask) {
            ret = solve(i) & solve(mask ^ i);
            if (ret == 1) break;
        }
        return dp[mask] = ret;
    }
    static ArrayList<Integer> dfs2(int mask) {
        ArrayList<Integer> ret = new ArrayList<>();
        if (good[mask]) {
            ret.add(mask);
            return ret;
        }
        for (int i = (mask - 1) & mask; i > 0; i = (i - 1) & mask) {
            if (dp[i] == 1 && dp[mask ^ i] == 1) {
                ArrayList<Integer> one = dfs2(i);
                ArrayList<Integer> two = dfs2(mask ^ i);
                ret.addAll(one); ret.addAll(two);
                break;
            }
        }
        return ret;
    }

    static boolean dfs(int cur) {
        vis[cur] = 1; boolean ret = false;
        for (Integer next: adj[cur]) {
            if (vis[next] == 0) {
                boolean cycle = dfs(next);
                if (cycle) {
                    if (!cy.contains(cur)) {
                        cy.add(cur);
                        ret = true; break;
                    }
                }
            } else if (vis[next] == 1) {
                cy.add(next);
                cy.add(cur);
                if (next != cur) ret = true;
                break;
            }
        }
        vis[cur] = 2;
        return ret;
    }

    //-----------MyScanner class for faster input----------
    public static class MyScanner {
        BufferedReader br;
        StringTokenizer st;

        public MyScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while (st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }

    }

}


import java.io.*;
import java.util.*;

public class Main {

    static class Reader
    {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        public Reader()
        {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public Reader(String file_name) throws IOException
        {
            din = new DataInputStream(new FileInputStream(file_name));
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        public String readLine() throws IOException
        {
            byte[] buf = new byte[64]; // line length
            int cnt = 0, c;
            while ((c = read()) != -1)
            {
                if (c == '\n')
                    break;
                buf[cnt++] = (byte) c;
            }
            return new String(buf, 0, cnt);
        }

        public int nextInt() throws IOException
        {
            int ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do
            {
                ret = ret * 10 + c - '0';
            }  while ((c = read()) >= '0' && c <= '9');

            if (neg)
                return -ret;
            return ret;
        }

        public long nextLong() throws IOException
        {
            long ret = 0;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();
            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');
            if (neg)
                return -ret;
            return ret;
        }

        public double nextDouble() throws IOException
        {
            double ret = 0, div = 1;
            byte c = read();
            while (c <= ' ')
                c = read();
            boolean neg = (c == '-');
            if (neg)
                c = read();

            do {
                ret = ret * 10 + c - '0';
            }
            while ((c = read()) >= '0' && c <= '9');

            if (c == '.')
            {
                while ((c = read()) >= '0' && c <= '9')
                {
                    ret += (c - '0') / (div *= 10);
                }
            }

            if (neg)
                return -ret;
            return ret;
        }

        private void fillBuffer() throws IOException
        {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1)
                buffer[0] = -1;
        }

        private byte read() throws IOException
        {
            if (bufferPointer == bytesRead)
                fillBuffer();
            return buffer[bufferPointer++];
        }

        public void close() throws IOException
        {
            if (din == null)
                return;
            din.close();
        }
    }

    public static void main(String[] args) throws IOException {
        Reader sc = new Reader();
        int k = sc.nextInt();
        int[][] buckets = new int[k][];
        long[] bucketSum = new long[k];
        Map<Integer, Integer> map = new HashMap<>(k * 10000);
        long target = 0;
        for (int i = 0; i < k; i++) {
            int n = sc.nextInt();
            int[] arr = new int[n];
            for (int j = 0; j < n; j++) {
                arr[j] = sc.nextInt();
                target += arr[j];
                map.put(arr[j], i);
                bucketSum[i] += arr[j];
            }
            buckets[i] = arr;
        }
        if ((target % k) != 0) {
            System.out.println("No");
            return;
        } else {
            target /= k;
        }

        int[] bitmask = new int[1 << (k )];
        Arrays.fill(bitmask, -1);

        for (int i = 0; i < k; i++) {
            for (int j = 0; j < buckets[i].length; j++) {
                int start = buckets[i][j];
                int next = (int) (target - bucketSum[i]) + start;

                Set<Integer> visited = new HashSet<>();
                Set<Integer> visitedBuckets = new HashSet<>();

                visited.add(start);
                visitedBuckets.add(i);
                int bitset = 1 << i;

                while (map.containsKey(next)) {
                    int bucket = map.get(next);
                    if (start == next) {
                        bitmask[bitset] = start;
                        break;
                    } else if (visited.contains(next)) {
                        break;
                    } else if (visitedBuckets.contains(bucket)) {
                        break;
                    }
                    visited.add(next);
                    visitedBuckets.add(bucket);
                    next = (int) (target - bucketSum[bucket]) + next;
                    bitset |= 1 << bucket;
                }
            }
        }

        boolean[] dp = new boolean[1 << (k ) ];
        Arrays.fill(dp, false);
        int[] build = new int[1 << k];
        Arrays.fill(build, -1);

        for (int i = 0; i < dp.length; i++) {
            dp[i] = bitmask[i] != -1;
        }
        for (int m = 0; m < (1 << k); m++) {
            if (!dp[m]) {
                for (int s = m; s != 0; s = (s - 1) & m) {
                    if (dp[s] && dp[(m ^ s)])   {
                        dp[m] = true;
                        build[m] = s;
                        break;
                    }
                }
            }
        }
        System.out.println(dp[dp.length - 1] ? "Yes" : "No");
        ArrayList<Integer> path = new ArrayList<>();
        rec(path, build, bitmask, (1 << k) - 1);

        int[] picked = new int[k];
        int[] out = new int[k];
        if (dp[dp.length - 1]) {
            for (int i : path) {
                int prev = i;
                int next = (int) (target - bucketSum[map.get(prev)]) + prev;
                picked[map.get(next)] = next;
                out[map.get(next)] = map.get(prev);
                while (next != i) {
                    int t = next;
                    next = (int) (target - bucketSum[map.get(next)]) + next;
                    prev = t;
                    out[map.get(next)] = map.get(prev);
                    picked[map.get(next)] = next;

                }
            }
            for (int i = 0; i < out.length; i++) {
                System.out.println((picked[i]) + " " + (out[i] + 1));
            }
        }
    }

    public static void rec(ArrayList<Integer> path, int[] build, int[] bitmask, int i) {
        if (!(i >= 0 && i < bitmask.length)) {
            return;
        }
        if (bitmask[i] != -1) {
            path.add(bitmask[i]);
        } else {
            rec(path, build, bitmask, build[i]);
            rec(path, build, bitmask, i ^ build[i]);
        }
    }
}


import java.io.*;
import java.util.*;

public class E implements Runnable {
	public static void main (String[] args) {new Thread(null, new E(), "_cf", 1 << 28).start();}

	HashMap<Integer, Integer> valToNode, nodeToVal, whichBox;
	int N, ptsTo[], cycleMask[], dfsStack[], tempList[];
	ArrayDeque<Integer> stack = new ArrayDeque<>();

	public void run() {
		FastScanner fs = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		System.err.println("");

		valToNode = new HashMap<>();
		nodeToVal = new HashMap<>();
		whichBox = new HashMap<>();

		int K = fs.nextInt();
		int[][] vals = new int[K][], valToNode2 = new int[K][];
		long[] sums = new long[K];
		long total = 0;

		for(int i = 0; i < K; i++) {
			int size = fs.nextInt();
			vals[i] = new int[size];
			valToNode2[i] = new int[size];
			for(int j = 0; j < size; j++) {
				vals[i][j] = fs.nextInt();
				sums[i] += vals[i][j];
				valToNode2[i][j] = valToNode.size();
				valToNode.put(vals[i][j], valToNode.size());
				nodeToVal.put(valToNode.size()-1, vals[i][j]);
				whichBox.put(vals[i][j], i);
			}
			total += sums[i];
		}
		if(total % K != 0) {
			System.out.println("No");
			return;
		}
		long perGroup = total/K;

		N = valToNode.size();
		ptsTo = new int[N];
		for(int i = 0; i < K; i++) {
			for(int j = 0; j < vals[i].length; j++) {
				long newSum = perGroup - (sums[i]-vals[i][j]);
				if(newSum > (int)1e9 || newSum < (int)-1e9) continue;
				if(valToNode.containsKey((int)newSum)) {
					ptsTo[valToNode.get(vals[i][j])] = valToNode.get((int)newSum);
				}
				else ptsTo[valToNode.get(vals[i][j])] = -1;
			}
		}

		tempList = new int[N];
		dfsStack = new int[N];
		cycleMask = new int[N];

		for(int i = 0; i < K; i++) {
			for(int j = 0; j < vals[i].length; j++) {
				int node = valToNode.get(vals[i][j]);
				if(dfsStack[node] == 0) dfs(node);
			}
		}

		int[] goodMask = new int[1<<K];
		Arrays.fill(goodMask, -1); goodMask[0] = 0;
		for(int mask = 1; mask < goodMask.length; mask++) {
			int idx = Integer.numberOfTrailingZeros(Integer.lowestOneBit(mask));
			for(int i = 0; i < vals[idx].length; i++) {
				int node = valToNode2[idx][i];
				if(cycleMask[node] == mask) {
					goodMask[mask] = node;
					break;
				}
			}
		}

		int[] dp = new int[1<<K];
		Arrays.fill(dp, -1); dp[0] = 0;
		for(int mask = 1; mask < dp.length; mask++) {
			if(goodMask[mask] != -1) {
				dp[mask] = mask;
				continue;
			}
			for(int sub = mask; sub != 0; sub = (sub-1)&mask) {
				if(goodMask[sub] == -1) continue;
				int newMask = mask-sub;
				if(dp[newMask] == -1) continue;

				dp[mask] = sub;
				break;
			}
		}

		if(dp[dp.length-1] == -1) out.println("No");
		else {
			int[][] res = new int[K][2];
			for(int[] x : res) Arrays.fill(x, -1);
			int curMask = dp.length-1;
			while(curMask > 0) {
				int temp = dp[curMask];
				int curNode = goodMask[temp];

				while(temp > 0) {
					int curVal = nodeToVal.get(curNode), curBox = whichBox.get(curVal);
					res[curBox][0] = curVal;
					int goingTo = ptsTo[curNode], goingVal = nodeToVal.get(goingTo), goingBox = whichBox.get(goingVal);
					res[goingBox][1] = curBox;
					curNode = ptsTo[curNode];
					temp -= 1<<curBox;
				}

				curMask -= dp[curMask];
			}

			out.println("Yes");
			for(int i = 0; i < K; i++) {
				if(res[i][1] == -1) throw null;
				out.printf("%d %d\n", res[i][0], res[i][1]+1);
			}
		}

		out.close();
	}

	void dfs(int node) {
		dfsStack[node] = 1;
		stack.addLast(node);
		int goTo = ptsTo[node];
		if(goTo == -1) {
			while(!stack.isEmpty()) {
				cycleMask[stack.pollLast()] = -1;
			}
		}
		else {
			if(dfsStack[goTo] == 1) {
				int ptr = 0, mask = 0, conflict = 0;
				while(!stack.isEmpty()) {
					int now = stack.pollLast(), val = nodeToVal.get(now), box = whichBox.get(val);
					tempList[ptr++] = now;
					if((mask & (1<<box)) > 0) conflict = 1;
					mask |= 1<<box;

					if(now == goTo) break;
				}
				while(!stack.isEmpty()) {
					cycleMask[stack.pollLast()] = -1;
				}
				for(int i = 0; i < ptr; i++) {
					int now = tempList[i];
					if(conflict > 0) cycleMask[now] = -1;
					else cycleMask[now] = mask;
				}
			}
			else if(dfsStack[goTo] == 2) {
				while(!stack.isEmpty()) {
					cycleMask[stack.pollLast()] = -1;
				}
			}
			else {
				dfs(goTo);
			}
		}

		dfsStack[node] = 2;
	}

	class FastScanner {
		public int BS = 1<<16;
		public char NC = (char)0;
		byte[] buf = new byte[BS];
		int bId = 0, size = 0;
		char c = NC;
		double num = 1;
		BufferedInputStream in;

		public FastScanner() {
			in = new BufferedInputStream(System.in, BS);
		}

		public FastScanner(String s) {
			try {
				in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
			}
			catch (Exception e) {
				in = new BufferedInputStream(System.in, BS);
			}
		}

		public char nextChar(){
			while(bId==size) {
				try {
					size = in.read(buf);
				}catch(Exception e) {
					return NC;
				}
				if(size==-1)return NC;
				bId=0;
			}
			return (char)buf[bId++];
		}

		public int nextInt() {
			return (int)nextLong();
		}

		public long nextLong() {
			num=1;
			boolean neg = false;
			if(c==NC)c=nextChar();
			for(;(c<'0' || c>'9'); c = nextChar()) {
				if(c=='-')neg=true;
			}
			long res = 0;
			for(; c>='0' && c <='9'; c=nextChar()) {
				res = (res<<3)+(res<<1)+c-'0';
				num*=10;
			}
			return neg?-res:res;
		}

		public double nextDouble() {
			double cur = nextLong();
			return c!='.' ? cur:cur+nextLong()/num;
		}

		public String next() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c>32) {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public String nextLine() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c!='\n') {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public boolean hasNext() {
			if(c>32)return true;
			while(true) {
				c=nextChar();
				if(c==NC)return false;
				else if(c>32)return true;
			}
		}

		public int[] nextIntArray(int n) {
			int[] res = new int[n];
			for(int i = 0; i < n; i++) res[i] = nextInt();
			return res;
		}

	}

}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Map;
import java.io.BufferedReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastScanner in = new FastScanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskC solver = new TaskC();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskC {
        int n;
        int[] bitCount;
        long neededSum;
        long[] sums;
        Map<Long, Integer> where;

        public void solve(int testNumber, FastScanner in, PrintWriter out) {
            n = in.nextInt();
            int[][] a = new int[n][];
            neededSum = 0;
            sums = new long[n];
            for (int i = 0; i < n; i++) {
                int k = in.nextInt();
                a[i] = new int[k];
                for (int j = 0; j < k; j++) {
                    a[i][j] = in.nextInt();
                    neededSum += a[i][j];
                    sums[i] += a[i][j];
                }
            }

            if (neededSum % n != 0) {
                out.println("No");
                return;
            }
            neededSum /= n;

            where = new HashMap<>();
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < a[i].length; j++) {
                    where.put((long) a[i][j], i);
                }
            }
            bitCount = new int[1 << n];
            for (int i = 0; i < bitCount.length; i++) {
                bitCount[i] = Integer.bitCount(i);
            }

            Entry[][] cycleSol = new Entry[1 << n][];

            List<Entry> sol = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                for (int x : a[i]) {
                    search(i, i, x, x, 0, 0, sol, cycleSol);
                }
            }

            boolean[] can = new boolean[1 << n];
            int[] via = new int[1 << n];
            can[0] = true;
            for (int mask = 0; mask < 1 << n; mask++) {
                for (int submask = mask; submask > 0; submask = (submask - 1) & mask) {
                    if (cycleSol[submask] != null && can[mask ^ submask]) {
                        can[mask] = true;
                        via[mask] = submask;
                    }
                }
            }

            if (!can[(1 << n) - 1]) {
                out.println("No");
                return;
            }

            int[][] ans = new int[n][2];
            for (int mask = (1 << n) - 1; mask > 0; ) {
                int sm = via[mask];
                mask ^= sm;

                for (Entry e : cycleSol[sm]) {
                    ans[e.from][0] = e.what;
                    ans[e.from][1] = e.to + 1;
                }
            }

            out.println("Yes");
            for (int i = 0; i < n; i++) {
                out.println(ans[i][0] + " " + ans[i][1]);
            }
        }

        private void search(int start, int cur, long fromStart, long fromCur, int hasIn, int hasOut, List<Entry> sol, Entry[][] cycleSol) {
            for (int i = 0; i < n; i++) {
                if ((hasIn & (1 << i)) > 0) {
                    continue;
                }
                if ((hasOut & (1 << cur)) > 0) {
                    continue;
                }
                long fromI = sums[i] + fromCur - neededSum;
                Integer w = where.get(fromI);
                if (w == null || w != i) {
                    continue;
                }
                sol.add(new Entry(cur, i, (int) fromCur));
                int nHasIn = hasIn | (1 << i);
                int nHasOut = hasOut | (1 << cur);
                if (i == start && fromI == fromStart) {
                    cycleSol[nHasOut] = sol.toArray(new Entry[0]);
                }
                search(start, i, fromStart, fromI, nHasIn, nHasOut, sol, cycleSol);
                sol.remove(sol.size() - 1);
            }
        }

        class Entry {
            int from;
            int to;
            int what;

            Entry(int from, int to, int what) {
                this.from = from;
                this.to = to;
                this.what = what;
            }

            public String toString() {
                return from + " " + to + " " + what;
            }

        }

    }

    static class FastScanner {
        private BufferedReader in;
        private StringTokenizer st;

        public FastScanner(InputStream stream) {
            in = new BufferedReader(new InputStreamReader(stream));
        }

        public String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    String rl = in.readLine();
                    if (rl == null) {
                        return null;
                    }
                    st = new StringTokenizer(rl);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return st.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

    }
}


import java.io.*;
import java.util.*;
import java.util.stream.*;

public class a implements Runnable{

    public static void main(String[] args) {
        new Thread(null, new a(), "process", 1<<26).start();
    }
	public void run() {
		FastReader scan = new FastReader();
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		//PrintWriter out = new PrintWriter("file.out");
		Task solver = new Task();
		//int t = scan.nextInt();
		int t = 1;
		for(int i = 1; i <= t; i++) solver.solve(i, scan, out);
		out.close();
	}

	static class Task {
		static final int inf = Integer.MAX_VALUE;

		public void solve(int testNumber, FastReader sc, PrintWriter pw) {
			//CHECK FOR QUICKSORT TLE
			//***********************//
			//CHECK FOR INT OVERFLOW
			//***********************//
			int n = sc.nextInt();
			int[][] arr = new int[n][];
			long sums[] = new long[n];
			HashMap<Integer, Integer> map1 = new HashMap<>();
			HashMap<Integer, Integer> map2 = new HashMap<>();
			ArrayList<Integer> arrs = new ArrayList<Integer>();
			arrs.add(0);
			int incc = 1;
			long sum = 0;
			for(int i = 0; i < n; i++) {
				int k = sc.nextInt();
				arr[i] = new int[k];
				for(int j = 0; j < k; j++) {
					sum += (arr[i][j] = sc.nextInt());
					sums[i] += arr[i][j];
					map1.put(arr[i][j], incc++);
					map2.put(arr[i][j], i);
					arrs.add(arr[i][j]);
				}
			}
			if(sum % n != 0) {
				pw.println("No");
				return;
			}
			cycle[] masktocyc = new cycle[1<<n];
			long goal = sum / n;
			ArrayList<cycle> cycs = new ArrayList<cycle>();
			int[] graph = new int[incc];
			l:
			for(int i = 1; i < incc; i++) {
				cycle c = new cycle();
				int curr = i;
				int val = arrs.get(i);
				int ind = map2.get(val);
				if(graph[i] != 0) continue;
				do {
					long ch = (goal - sums[ind] + val);
					if(ch > inf || ch < -inf || !map1.containsKey((int)ch)) {
						continue l;
					}
					val = (int)(ch);
					graph[curr] = map1.get(val);
					//pw.println(curr + " - " + map1.get(ch));
					curr = map1.get(val);
					c.add(ind, val);
					ind = map2.get(val);
				}
				while(graph[curr] == 0);
				for(tup x : c.arr) {
					if(sums[x.a] - arrs.get(curr) + x.b == goal) break;
					c.mask -= (1<<x.a);
					x.a = -inf;
					x.b = -inf;
				}
				int[] freq = new int[15];
				for(tup x : c.arr) {
					if(x.a >= 0) {
						freq[x.a]++;
						if(freq[x.a] > 1) continue l;
					}
				}
				//for(tup x : c.arr) System.out.printf("%d %d%n", x.a, x.b);
				//System.out.println(c.mask);
				cycs.add(c);
				masktocyc[c.mask] = c;
			}

			ArrayList<cycle>[] dp = new ArrayList[1<<n];
			for(int m = 0; m < (1<<n); m++) {
				dp[m] = new ArrayList<cycle>();
				if(masktocyc[m] != null) {
					dp[m].add(masktocyc[m]);
					continue;
				}
				for(int s = m; s > 0; s = (s - 1) & m) {
					if(dp[s].size() > 0 && dp[m ^ s].size() > 0) {
						dp[m].addAll(dp[s]);
						dp[m].addAll(dp[m ^ s]);
						break;
					}
				}
			}
			if(dp[(1<<n) - 1].size() > 0) {
				pw.println("Yes");
				int[] ans1 = new int[n];
				int[] ans2 = new int[n];
				for(cycle x : dp[(1<<n) - 1]) {
					for(tup y : x.arr) {
						if(y.b != -inf) {
							ans1[map2.get(y.b)] = y.a+1;
							ans2[map2.get(y.b)] = y.b;
						}
					}
				}
				for(int i = 0; i < n; i++) {
					pw.printf("%d %d%n", ans2[i], ans1[i]);
				}
			}
			else pw.println("No");
		}
		static class cycle {
			ArrayList<tup> arr = new ArrayList<>();
			int mask = 0;
			public cycle(){}
			void add(int ind, int val) {
				arr.add(new tup(ind, val));
				mask += (1<<ind);
			}
		}
	}
	static long binpow(long a, long b, long m) {
		a %= m;
		long res = 1;
		while (b > 0) {
			if ((b & 1) == 1)
				res = res * a % m;
			a = a * a % m;
			b >>= 1;
		}
		return res;
	}
	static void sort(int[] x){
		shuffle(x);
		Arrays.sort(x);
	}
	static void sort(long[] x){
		shuffle(x);
		Arrays.sort(x);
	}
	static class tup implements Comparable<tup>{
		int a, b;
		tup(int a,int b){
			this.a=a;
			this.b=b;
		}
		@Override
		public int compareTo(tup o){
			return Integer.compare(o.b,b);
		}
	}
	static void shuffle(int[] a) {
		Random get = new Random();
		for (int i = 0; i < a.length; i++) {
			int r = get.nextInt(i + 1);
			int temp = a[i];
			a[i] = a[r];
			a[r] = temp;
		}
	}

	static void shuffle(long[] a) {
		Random get = new Random();
		for (int i = 0; i < a.length; i++) {
			int r = get.nextInt(i + 1);
			long temp = a[i];
			a[i] = a[r];
			a[r] = temp;
		}
	}

	static class FastReader {
		BufferedReader br;
		StringTokenizer st;

		public FastReader() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}

		public FastReader(String s) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(new File(s)));
		}

		String next() {
			while (st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		String nextLine() {
			String str = "";
			try {
				str = br.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return str;
		}
	}

}