Problem:
>土地分割

ハウジングメーカーの山田ハウスは、新たな目玉商品として、学校や病院など環境が充実している緑ホームタウンの分譲地を売り出しました。この分譲地は複数の区画に分割されており、好きなだけ購入できますが、購入する区画を合わせた土地の形状は長方形(正方形を含む)でなければなりません。

山田ハウスは、全区画が完売した分譲地を管理するため購入者ごとに境界線を引き、その区画の 1つに購入者番号を書いた看板を設置しておきました。境界線は地面に木の枝で線を引いただけのものであったため、数日後の豪雨により消えてしまい看板だけが残りました。図 1 は看板のあった区画に、その区画を買った購入者番号を記したものです。これでは分譲地がどのように買われたか分かりません。救いは事務所の引き出しにあった購入者番号 b と購入区画数 k のメモ(図 2)が見つかったことです。

図１（左）：看板の配置、図2（右）：メモ

プログラマーであるあなたは、プログラムを書いて山田ハウスを助けることになりました。分譲地の大きさ X × Y 、購入者数 n 、メモの情報 b、 k 、及び看板の位置情報 s を入力とし、図 3 に示すように各区画の購入者を出力するプログラムを作成してください。

図3：各区画の購入者

与えられた情報について、以下の場合は NA と出力します。

区画を区別する方法が存在しない場合

区画を区別する方法が複数存在する場合

Input

複数のデータセットの並びが入力として与えられます。入力の終わりはゼロが３つの行で示されます。各データセットは以下の形式で与えられます。

X Y n
b1 k1
b2 k2
:
bn kn
s11 s21 ... sX1
s12 s22 ... sX2
:
s1Y s2Y ... sXY

1 行目にX, Y, n (1 ≤ X, Y ≤ 10, 1 ≤ n ≤ 15) が与えられます。続く n 行にメモの i 行目に書かれた情報 bi (1 ≤ bi ≤ n), ki (1 ≤ ki ≤ 100) が与えられます。

続く Y 行に区画情報の i 行目の情報 sij が与えられます。sij はi 行目の左から j 番目の区画の看板情報を表します。看板の情報 sij として、その区画に看板が無い場合は 0 、看板がある場合はその区画の購入者番号が与えられます。

データセットの数は 50 を超えません。

Output

入力データセットごとに、購入者情報またはNA を出力します。

Sample Input

5 4 6
1 6
2 4
3 3
4 4
5 1
6 2
0 0 1 0 0
0 0 0 2 0
0 0 0 3 0
0 4 5 0 6
3 3 1
1 9
0 0 1
0 0 0
0 0 0
4 4 4
1 6
2 2
3 4
4 4
0 1 0 0
0 0 0 2
0 0 3 0
0 4 0 0
0 0 0

Output for the Sample Input

1 1 1 2 2
1 1 1 2 2
4 4 3 3 3
4 4 5 6 6
1 1 1
1 1 1
1 1 1
NA

Solution in JAVA (judge verdict: WA: Presentation Error)


import java.awt.geom.*;
import java.util.*;
public class Main {
	
	boolean [] used;
	boolean flg, dup;
	int n,w,h, deepsize;
	int [][] data, ans;
	int [] hash;
	C[][] cand;
	P [] point;
	
	class C{
		HashSet<Integer> list;

		public C(HashSet<Integer> list) {
			this.list = list;
		}
	}
	
	class P{
		int x,y;

		public P(int x, int y) {
			this.x = x;
			this.y = y;
		}
		
	}
	
	private void doit(){
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()){
			w = sc.nextInt();
			h = sc.nextInt();
			n = sc.nextInt();
			if((w|h|n) == 0) break;
			hash = new int[n+1];
			deepsize = n;
			for(int i = 0; i < n; i++){
				int b = sc.nextInt();
				int k = sc.nextInt();
				hash[b] = k;
				if(k == 1) deepsize--;
			}
			data = new int[h][w];
			point = new P[n+1];
			for(int i = 0; i < h; i++){
				for(int j = 0; j < w; j++){
					data[i][j] = sc.nextInt();
					if(data[i][j] > 0){
						point[data[i][j]] = new P(j, i);
					}
				}
			}
			
			used = new boolean[n+1];
			flg = false;
			dup = true;
			ans = new int[h][w];
			dfs(1);
			if(flg && dup){
				for(int i = 0; i < h; i++){
					for(int j = 0; j < w; j++){
						System.out.print(ans[i][j] + " ");
					}
					System.out.println();
				}
			}
			else{
				System.out.println("NA");
			}
		}
	}
	

	private void dfs(int deep) {
		if(deep == n + 1){
			if(flg){
				dup =false;
				return;
			}
			flg = true;
			for(int i = 0; i < h; i++){
				ans[i] = data[i].clone();
			}
			return ;
		}
		if(hash[deep] == 1){
			dfs(deep+1);
			return ;
		}
		
		for(int i = 0; i < h; i++){
			for(int j = 0; j < w; j++){
				if(data[i][j] != 0 && data[i][j] != deep) continue;
				
				for(int k = i; k < h; k++){
					for(int l = j; l < w; l++){
						int dis = calcdis(j, i, l, k);
						if(used[deep]) continue;
						if(dis == hash[deep]){
							
							boolean res = check(j,i,l,k, deep);
							if(! res) continue;
							set(j,i,l,k, deep);
							used[deep] = true;
							dfs(deep + 1);
							used[deep] = false;
							set(j,i,l,k,0);
							data[point[deep].y][point[deep].x] = deep;
						}
					}
				}
				
			}
		}
		
		
	}
	
	private void disp(){
		for(int i = 0; i < h; i++){
			for(int j = 0; j < w; j++){
				System.out.print(data[i][j] + " ");
			}
			System.out.println();
		}
	}


	private void set(int x1, int y1, int x2, int y2, int num) {
		
		for(int i = y1; i <= y2; i++){
			for(int j = x1; j <= x2; j++){
				data[i][j] = num;
			}
		}
	}


	private boolean check(int x1, int y1, int x2, int y2, int num) {
		boolean issameC = false;
		for(int i = y1; i <= y2; i++){
			for(int j = x1; j <= x2; j++){
				if(data[i][j] == num){
					issameC = true;
				}
				else if(data[i][j] != 0){
					return false;
				}
			}
		}
		if(issameC) return true;
		return false;
	}


	private int calcdis(int x1, int y1, int x2, int y2) {
		int res = (Math.abs(x1 - x2) + 1) * (Math.abs(y1 - y2) + 1);
		return res;
	}


	public static void main(String[] args) {
		Main obj = new Main();
		obj.doit();
	}
}