package main
import (
"bufio"
"container/heap"
"fmt"
"os"
"strconv"
)
type Item struct {
i, j int
d int64
}
type PriorityQueue []Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool { return pq[i].d < pq[j].d }
func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] }
func (pq *PriorityQueue) Push(x interface{}) {
*pq = append(*pq, x.(Item))
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
*pq = old[0 : n-1]
return item
}
type pair struct{ i, j int }
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024)
scanner.Split(bufio.ScanWords)
nextInt := func() int {
scanner.Scan()
v, _ := strconv.Atoi(scanner.Text())
return v
}
nextString := func() string {
scanner.Scan()
return scanner.Text()
}
if !scanner.Scan() {
return
}
tCases, _ := strconv.Atoi(scanner.Text())
dirs4 := [4][2]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}
dirs8 := [8][2]int{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}
for t := 0; t < tCases; t++ {
n := nextInt()
r := nextInt()
k := nextInt()
a := make([][]int, n)
for i := 0; i < n; i++ {
a[i] = make([]int, n)
for j := 0; j < n; j++ {
a[i][j] = nextInt()
}
}
c := make([]string, n)
for i := 0; i < n; i++ {
c[i] = nextString()
}
visited := make([][]bool, n)
for i := 0; i < n; i++ {
visited[i] = make([]bool, n)
}
q := make([]pair, 0, n*n)
pathExists := func(limit int) bool {
if a[0][0] > limit || a[r-1][n-1] > limit {
return false
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
visited[i][j] = false
}
}
q = q[:0]
q = append(q, pair{0, 0})
visited[0][0] = true
head := 0
for head < len(q) {
curr := q[head]
head++
if curr.i == r-1 && curr.j == n-1 {
return true
}
for _, dir := range dirs4 {
ni, nj := curr.i+dir[0], curr.j+dir[1]
if ni >= 0 && ni < n && nj >= 0 && nj < n && !visited[ni][nj] && a[ni][nj] <= limit {
visited[ni][nj] = true
q = append(q, pair{ni, nj})
}
}
}
return false
}
lowM, highM := 1, 1000000
DM := -1
for lowM <= highM {
mid := (lowM + highM) / 2
if pathExists(mid) {
DM = mid
highM = mid - 1
} else {
lowM = mid + 1
}
}
reach1 := make([][]bool, n)
for i := 0; i < n; i++ {
reach1[i] = make([]bool, n)
}
q = q[:0]
q = append(q, pair{0, 0})
reach1[0][0] = true
head := 0
for head < len(q) {
curr := q[head]
head++
for _, dir := range dirs4 {
ni, nj := curr.i+dir[0], curr.j+dir[1]
if ni >= 0 && ni < n && nj >= 0 && nj < n && !reach1[ni][nj] && a[ni][nj] <= DM {
reach1[ni][nj] = true
q = append(q, pair{ni, nj})
}
}
}
reach2 := make([][]bool, n)
for i := 0; i < n; i++ {
reach2[i] = make([]bool, n)
}
q = q[:0]
q = append(q, pair{r - 1, n - 1})
reach2[r-1][n-1] = true
head = 0
for head < len(q) {
curr := q[head]
head++
for _, dir := range dirs4 {
ni, nj := curr.i+dir[0], curr.j+dir[1]
if ni >= 0 && ni < n && nj >= 0 && nj < n && !reach2[ni][nj] && a[ni][nj] <= DM {
reach2[ni][nj] = true
q = append(q, pair{ni, nj})
}
}
}
inVpath := make([][]bool, n)
for i := 0; i < n; i++ {
inVpath[i] = make([]bool, n)
for j := 0; j < n; j++ {
if reach1[i][j] && reach2[i][j] {
inVpath[i][j] = true
}
}
}
dist := make([][]int64, n)
for i := 0; i < n; i++ {
dist[i] = make([]int64, n)
}
pq := make(PriorityQueue, 0, n*n)
check := func(X int) bool {
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
dist[i][j] = 1e18
}
}
pq = pq[:0]
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if X > DM && inVpath[i][j] {
continue
}
var w int64 = 0
if a[i][j] < X {
if c[i][j] == '1' {
w = int64(X - a[i][j])
} else {
w = 1e18
}
}
isP1 := (i == 0 || j == 0 || (j == n-1 && i <= r-1))
if isP1 && w <= int64(k) {
dist[i][j] = w
heap.Push(&pq, Item{i, j, w})
}
}
}
for pq.Len() > 0 {
curr := heap.Pop(&pq).(Item)
i, j, d := curr.i, curr.j, curr.d
if d > dist[i][j] {
continue
}
isP2 := (i == n-1 || (j == n-1 && i >= r-1))
if isP2 {
return true
}
for _, dir := range dirs8 {
ni, nj := i+dir[0], j+dir[1]
if ni >= 0 && ni < n && nj >= 0 && nj < n {
if X > DM && inVpath[ni][nj] {
continue
}
var w int64 = 0
if a[ni][nj] < X {
if c[ni][nj] == '1' {
w = int64(X - a[ni][nj])
} else {
w = 1e18
}
}
if w != 1e18 && d+w <= int64(k) && d+w < dist[ni][nj] {
dist[ni][nj] = d + w
heap.Push(&pq, Item{ni, nj, dist[ni][nj]})
}
}
}
}
return false
}
ansF := 0
lowF, highF := 1, 2000005
for lowF <= highF {
mid := (lowF + highF) / 2
if check(mid) {
ansF = mid
lowF = mid + 1
} else {
highF = mid - 1
}
}
fmt.Printf("%d %d\n", DM, ansF)
}
}