source_code: 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());
  		}
  	}
  	
  	
  }
  