use std::io::*;
use std::str::FromStr;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

fn dfs(
    y: usize,
    x: usize,
    xy: &Vec<(i32, i32)>,
    color: i32,
    visit: &mut Vec<Vec<i32>>,
    usable: &Vec<Vec<bool>>,
) -> (i32, i32) {
    let n = visit.len() / 2;
    assert!(visit[y][x] == -1);
    assert!(usable[y][x]);
    visit[y][x] = color;
    let mut ret = (color ^ 1, color);
    for &(dx, dy) in xy.iter() {
        let nx = x as i32 + dx;
        let ny = y as i32 + dy;
        if nx < 0 || nx >= n as i32 * 2 || ny < 0 || ny >= n as i32 * 2 {
            continue;
        }
        let nx = nx as usize;
        let ny = ny as usize;
        if visit[ny][nx] != -1 || !usable[ny][nx] {
            continue;
        }
        let nret = dfs(ny, nx, xy, color ^ 1, visit, usable);
        ret.0 += nret.0;
        ret.1 += nret.1;
    }
    ret
}

fn solve(n: usize, ds: Vec<i32>) {
    let mut usable = vec![vec![true; 2 * n]; 2 * n];
    for &d in ds.iter() {
        let mut xy = vec![];
        for x in 0..d + 1 {
            if x * x > d {
                break;
            }
            let rest = d - x * x;
            let y = (rest as f64).sqrt() as i32;
            if y * y == rest {
                xy.push((x, y));
                xy.push((-x, y));
                xy.push((x, -y));
                xy.push((-x, -y));
            }
        }
        xy.sort();
        xy.dedup();
        let mut visit = vec![vec![-1; 2 * n]; 2 * n];
        let mut cnt = (0, 0);
        for y in 0..2 * n {
            for x in 0..2 * n {
                if !usable[y][x] || visit[y][x] != -1 {
                    continue;
                }
                let ncnt = dfs(y, x, &xy, 0, &mut visit, &usable);
                cnt.0 += ncnt.0;
                cnt.1 += ncnt.1;
            }
        }
        let ban_color = if cnt.0 < cnt.1 { 0 } else { 1 };
        // println!("{:?} {}", cnt, ban_color);
        for y in 0..2 * n {
            for x in 0..2 * n {
                if visit[y][x] == ban_color {
                    usable[y][x] = false;
                }
            }
        }
    }
    let mut anss = vec![];
    'yloop: for y in 0..2 * n {
        for x in 0..2 * n {
            if usable[y][x] {
                anss.push((x, y));
                if anss.len() == n * n {
                    break 'yloop;
                }
            }
        }
    }

    // println!("{} {}", anss.len(), n * n);
    assert!(anss.len() == n * n);
    for i in 0..n * n {
        println!("{} {}", anss[i].0, anss[i].1);
    }
}

fn main() {
    let n = read::<usize>();
    let mut ds = vec![0; 2];
    ds[0] = read::<i32>();
    ds[1] = read::<i32>();
    solve(n, ds);
}

#[test]
fn search_xy() {
    {
        for d in 1..100 {
            let mut xy = vec![];
            for x in 0..d + 1 {
                if x * x > d {
                    break;
                }
                let rest = d - x * x;
                let y = (rest as f64).sqrt() as usize;
                if y * y == rest {
                    xy.push((x, y));
                }
            }
            println!("{} {} {:?}", d, xy.len(), xy);
        }
    }
}

#[test]
fn search() {
    for n in 1..30 {
        for d1 in 1..30 {
            for d2 in d1 + 1..30 {
                println!("{} {} {}", n, d1, d2);
                solve(n, vec![d1, d2]);
            }
        }
    }
}


Measured memory_bytes: 48380