// Arup Guha
// Solution to 2010 South East Regional Problem C: Data Recovery
// Started a long time ago, finished on 10/3/2014

// Basic solution idea: set up flow graph. Left nodes are rows, middle nodes are cells, right nodes are cols.
// Edges connect the row and column of every cell with a -1 with a capacity of 100. This gives us one feasible
// solution. Then, go through each -1 cell and use a bfs, searching for a cycle where you can +1, -1 +1, -1 in
// free cells where you adjust the valid solution into a new one. The smallest such cycle looks like a rectangle
// with -1s in its four corners in such a way that each number has the appropriate freedom to move up or
// down. You have to try both ways; adding 1 to your source, or subtracting 1 from it. If you find a cycle,
// all of those are indeterminant and you keep the -1s there. If there's no cycle, use the answer from the
// feasible solution.

import java.util.*;

public class c {

	public static int[][] grid;
	public static int[] realRowSums;
	public static int[] realColSums;
	public static int[] curRowSums;
	public static int[] curColSums;
	public static int[] numRowMiss;
	public static int[] numColMiss;
	public static int numR;
	public static int numC;

	public static void main(String[] args) {

		Scanner stdin = new Scanner(System.in);

		numR = stdin.nextInt();
		numC = stdin.nextInt();

		while (numR != 0) {

			// Read in grid.
			grid = new int[numR][numC];
			for (int i=0; i<numR; i++)
				for (int j=0; j<numC; j++)
					grid[i][j] = stdin.nextInt();

			// Read in the row and column sums.
			realRowSums = new int[numR];
			for (int i=0; i<numR; i++)
				realRowSums[i] = stdin.nextInt();

			realColSums = new int[numC];
			for (int i=0; i<numC; i++)
				realColSums[i] = stdin.nextInt();

			// Calculate the current sums.
			curRowSums = new int[numR];
			numRowMiss = new int[numR];
			for (int i=0; i<numR; i++)
				for (int j=0; j<numC; j++)
					if (grid[i][j] != -1)
						curRowSums[i] += grid[i][j];
					else
						numRowMiss[i]++;

			curColSums = new int[numC];
			numColMiss = new int[numC];
			for (int j=0; j<numC; j++)
				for (int i=0; i<numR; i++)
					if (grid[i][j] != -1)
						curColSums[j] += grid[i][j];
					else
						numColMiss[j]++;

			// Make flow graph.
			Edge[][] graph = makeGraph();

			// Create flow network and calculate flow (should be sum of direct edges to sink...)
			netflow flow = new netflow(graph, 0, graph.length-1);
			int sumFlow = flow.getMaxFlow();

			// Calculate one possible final grid.
			int[][] validGrid = getGrid(flow);

			// Use one solution and open squares to determine all solutions.
			int[][] finalGrid = solve(validGrid);

			// Print.
			for (int i=0; i<numR; i++) {
				for (int j=0; j<numC-1; j++)
					System.out.print(finalGrid[i][j]+" ");
				System.out.println(finalGrid[i][numC-1]);
			}

			numR = stdin.nextInt();
			numC = stdin.nextInt();
		}
	}

	// Returns the solution grid.
	public static int[][] solve(int[][] validGrid) {

		// Will store solution and locations that are impossible to determine uniquely.
		int[][] sol = new int[numR][numC];
		boolean[][] impossible = new boolean[numR][numC];

		// Forms the links between unsolved squares.
		ArrayList[] resGraph = formGraph();

		// Go to each spot.
		for (int i=0; i<numR; i++) {
			for (int j=0; j<numC; j++) {

				// Situations where we copy from grid.
				if (grid[i][j] !=-1 || impossible[i][j])
					sol[i][j] = grid[i][j];

				// Free squares to solve.
				else {

					// Look for cycle.
					LinkedList<Integer> path = bfs(i, j, resGraph, validGrid, 1);
					if (path == null) path = bfs(i, j, resGraph, validGrid, -1);

					// We've solved these as impossible to fill, so mark it.
					if (path != null) {

						// This can't be solved!
						sol[i][j] = -1;
						for (int k=0; k<path.size(); k++) {
						//	System.out.println("next path true is "+path.get(k));
							impossible[path.get(k)/numC][path.get(k)%numC] = true;
						}
					}

					// Fill in only correct solution.
					else
						sol[i][j] = validGrid[i][j];
				}
			}
		}

		return sol;
	}

	// Forms the residual graph, connecting cells on the same row and same column.
	public static ArrayList[] formGraph() {

		ArrayList[] graph = new ArrayList[numR*numC];
		for (int i=0; i<graph.length; i++)
			graph[i] = new ArrayList<Integer>();

		// Go through each row.
		for (int i=0; i<numR; i++) {

			// Find each item in this column that is unfilled.
			ArrayList<Integer> cols = new ArrayList<Integer>();
			for (int j=0; j<numC; j++)
				if (grid[i][j] == -1)
					cols.add(j);

			// Store links between them all.
			for (int j=0; j<cols.size(); j++) {
				for (int k=j+1; k<cols.size(); k++) {
					graph[i*numC+cols.get(j)].add(i*numC+cols.get(k));
					graph[i*numC+cols.get(k)].add(i*numC+cols.get(j));
				}
			}

		}

		// Go through each col.
		for (int j=0; j<numC; j++) {

			// Find each item in this column that is unfilled.
			ArrayList<Integer> rows = new ArrayList<Integer>();
			for (int i=0; i<numR; i++)
				if (grid[i][j] == -1)
					rows.add(i);

			// Store links between them all.
			for (int i=0; i<rows.size(); i++) {
				for (int k=i+1; k<rows.size(); k++) {
					graph[rows.get(i)*numC+j].add(rows.get(k)*numC+j);
					graph[rows.get(k)*numC+j].add(rows.get(i)*numC+j);
				}
			}

		}

		return graph;
	}

	public static LinkedList<Integer> bfs(int r, int c, ArrayList[] resGraph, int[][] validGrid, int offset) {

		// Silly case, but this is where I want to check it.
		if (!inbounds(validGrid[r][c]+offset)) return null;

		// Will store previous links and distance from source in bfs.
		int[] prev = new int[numR*numC];
		int[] dist = new int[numR*numC];

		// Set up whole bfs.
		LinkedList<Integer> q = new LinkedList<Integer>();
		q.offer(r*numC+c);
		boolean[] visited = new boolean[numR*numC];
		visited[r*numC+c] = true;

		// Run it.
		while (q.size() > 0) {

			// Get relevant information from next item.
			int next = q.poll();
			int nextD = dist[next];
			int nextR = next/numC;
			int nextC = next%numC;
			int nextOffset = nextD%2 == 1 ? offset: -offset;

			// Got to the right place.
			if (nextR != r && nextC == c) {

				// Found a solution - form and return.
				LinkedList<Integer> path = new LinkedList<Integer>();
				while (next != r*numC + c) {
					path.addFirst(next);
					next = prev[next];
				}
				path.addFirst(next);
				return path;
			}

			// Enqueue unvisited neighbors.
			for (int i=0; i<resGraph[next].size(); i++) {

				int node = (Integer)resGraph[next].get(i);

				// Upholding next row, next column order.
				if (nextD%2 == 0 && node/numC != nextR) continue;
				if (nextD%2 == 1 && node%numC != nextC) continue;

				// We should visit this one.
				if (!visited[node] && inbounds(validGrid[node/numC][node%numC] + nextOffset)) {
					visited[node] = true;
					dist[node] = nextD+1;
					prev[node] = next;
					q.offer(node);
				}
			}

		}

		return null;
	}

	// Returns true iff val is a valid value in our grid.
	public static boolean inbounds(int val) {
		return val >= 0 && val <= 100;
	}

	// Called after flow algorithm run. Returns reconstruction of grid.
	public static int[][] getGrid(netflow flowGraph) {

		int[][] ans = new int[numR][numC];

		int index = 0;
		for (int i=0; i<numR; i++) {
			for (int j=0; j<numC; j++) {

				if (grid[i][j] >= 0) ans[i][j] = grid[i][j];
				else {
					ans[i][j] = flowGraph.adjMat[1+numR+numC*i+j][0].flow;
					index++;
				}
			}
		}
		return ans;
	}

	// Creates the flow graph from the input data.
	public static Edge[][] makeGraph() {

		Edge[][] adj = new Edge[2+numR+numC+numR*numC][];

		// Flows from source to each row of unfilled value for that row.
		adj[0] = new Edge[numR];
		for (int i=0; i<numR; i++)
			adj[0][i] = new Edge(realRowSums[i]-curRowSums[i], i+1);

		// Flows of 100 from each row to each column for unfilled squares.
		for (int i=1; i<=numR; i++) {
			adj[i] = new Edge[numRowMiss[i-1]];
			int index = 0;
			for (int j=0; j<numC; j++) {
				if (grid[i-1][j] == -1)
					adj[i][index++] = new Edge(100, (i-1)*numC+j+1+numR );
			}
		}

		// Flow from each cell to its column.
		for (int i=numR+1; i<numR+1+numR*numC; i++) {
			adj[i] = new Edge[1];
			adj[i][0] = new Edge(100, numR+1+numR*numC + (i-numR-1)%numC);
		}

		// Flows from columns to sink equal to the unfilled values in each column.
		int offset = numR+1+numR*numC;
		for (int i= offset; i<adj.length-1; i++) {
			adj[i] = new Edge[1];
			adj[i][0] = new Edge(realColSums[i-offset]-curColSums[i-offset], adj.length-1);
		}

		return adj;
	}
}

/*** My awful network flow code is below ***/
class Edge {

	public int dest;
	public int capacity;
	public int flow;

	public Edge(int cap, int d) {
		capacity = cap;
		flow = 0;
		dest = d;
	}

	public int maxPushForward() {
		return capacity - flow;
	}

	public int maxPushBackward() {
		return flow;
	}

	public boolean pushForward(int moreflow) {

		// We can't push through this much flow.
		if (flow+moreflow > capacity)
			return false;

		// Push through.
		flow += moreflow;
		return true;
	}

	public boolean pushBack(int lessflow) {

		// Not enough to push back on.
		if (flow < lessflow)
			return false;

		flow -= lessflow;
		return true;
	}
}

class direction {

	public int prev;
	public boolean forward;

	public direction(int node, boolean dir) {
		prev = node;
		forward = dir;
	}

	public String toString() {
		if (forward)
			return "" + prev + "->";
		else
			return "" + prev + "<-";
	}
}

class netflow {

	public Edge[][] adjMat;
	private int source;
	private int dest;
	private HashMap[] lookup;
	private LinkedList[] backEdgeLookup;

	// Input matrix is edge list.
	public netflow(Edge[][] matrix, int start, int end) {

		// Set up easy stuff.
		adjMat = matrix;
		source = start;
		dest = end;
		lookup = new HashMap[matrix.length];

		// Allocate empty LLs.
		backEdgeLookup = new LinkedList[matrix.length];
		for (int i=0; i<matrix.length; i++)
			backEdgeLookup[i] = new LinkedList<Integer>();

		// Fill these in.
		for (int i=0; i<adjMat.length; i++) {

			lookup[i] = new HashMap<Integer,Integer>();
			for (int j=0; adjMat[i] != null && j<adjMat[i].length; j++) {
				lookup[i].put(adjMat[i][j].dest, j);
				backEdgeLookup[adjMat[i][j].dest].offer(i);
			}
		}
	}

	// All positive entries in flows should represent valid flows
	// between vertices. All other entries must be 0 or negative.
	public netflow(int[][] flows, int start, int end) {

		source = start;
		dest = end;
		adjMat = new Edge[flows.length][];
		lookup = new HashMap[flows.length];

		backEdgeLookup = new LinkedList[flows.length];
		for (int i=0; i<flows.length; i++)
			backEdgeLookup[i] = new LinkedList<Integer>();

		for (int i=0; i<flows.length; i++) {

			lookup[i] = new HashMap<Integer,Integer>();

			int numEdges = 0;
			for (int j=0; j<flows[i].length; j++)
				if (flows[i][j] > 0)
					numEdges++;

			adjMat[i] = new Edge[numEdges];

			int cnt = 0;
			for (int j=0; j<flows[i].length; j++) {

				// Fill in this flow.
				if (flows[i][j] > 0) {
					lookup[i].put(j, cnt);
					adjMat[i][cnt++] = new Edge(flows[i][j], j);
					backEdgeLookup[j].offer(i);
				}
			}
		}
	}

	public ArrayList<direction> findAugmentingPath() {

		// This will store the previous node visited in the BFS.
		direction[] prev = new direction[adjMat.length];
		boolean[] inQueue = new boolean[adjMat.length];
		for (int i=0; i<inQueue.length; i++)
			inQueue[i] = false;

		// The source has no previous node.
		prev[source] = new direction(-1, true);

		LinkedList<Integer> bfs_queue = new LinkedList<Integer>();
		bfs_queue.offer(new Integer(source));
		inQueue[source] = true;

		// Our BFS will go until we clear out the queue.
		while (bfs_queue.size() > 0) {

			// Add all the new neighbors of the current node.
			Integer next = bfs_queue.poll();

			if (adjMat[next] == null) continue;

			// Find all neighbors and add into the queue. These are forward edges.
			for (int i=0; i<adjMat[next].length; i++) {

				int item = adjMat[next][i].dest;
				if (!inQueue[item] && adjMat[next][i].maxPushForward() > 0) {
					bfs_queue.offer(item);
					inQueue[item] = true;
					prev[item] = new direction(next, true);
				}
			}

			// Now look for back edges.
			for (int i=0; i<backEdgeLookup[next].size(); i++) {

				int item = (Integer)backEdgeLookup[next].pollFirst();
				if (!inQueue[item] && lookup[item].containsKey(next) && adjMat[item][(Integer)(lookup[item].get(next))].maxPushBackward() > 0) {
					bfs_queue.offer(item);
					inQueue[item] = true;
					prev[item] = new direction(next, false);
				}
				backEdgeLookup[next].offer(item);
			}
		}

		// No augmenting path found.
		if (!inQueue[dest])
			return null;

		ArrayList<direction> path = new ArrayList<direction>();

		direction place = prev[dest];

		direction dummy = new direction(dest, true);
		path.add(dummy);

		// Build the path backwards.
		while (place.prev != -1) {
			path.add(place);
			place = prev[place.prev];
		}

		// Reverse it now.
		Collections.reverse(path);

		return path;
	}

	// Run the Max Flow Algorithm here.
	public int getMaxFlow() {

		int flow = 0;

		ArrayList<direction> nextpath = findAugmentingPath();

		// Loop until there are no more augmenting paths.
		while (nextpath != null) {

			// Check what the best flow through this path is.
			int this_flow = Integer.MAX_VALUE;
			for (int i=0; i<nextpath.size()-1; i++) {

				if (nextpath.get(i).forward) {
					this_flow = Math.min(this_flow, adjMat[nextpath.get(i).prev][(Integer)lookup[nextpath.get(i).prev].get(nextpath.get(i+1).prev)].maxPushForward());
				}
				else {
					this_flow = Math.min(this_flow, adjMat[nextpath.get(i+1).prev][(Integer)lookup[nextpath.get(i+1).prev].get(nextpath.get(i).prev)].maxPushBackward());
				}
			}

			// Now, put this flow through.
			for (int i=0; i<nextpath.size()-1; i++) {

				if (nextpath.get(i).forward) {
					adjMat[nextpath.get(i).prev][(Integer)lookup[nextpath.get(i).prev].get(nextpath.get(i+1).prev)].pushForward(this_flow);
				}
				else {
					adjMat[nextpath.get(i+1).prev][(Integer)lookup[nextpath.get(i+1).prev].get(nextpath.get(i).prev)].pushBack(this_flow);
				}
			}

			// Add this flow in and then get the next path.
			flow += this_flow;
			nextpath = findAugmentingPath();
		}

		return flow;
	}

}