第三次CCF計算機軟件能力認證題目:Z字形掃描

這是第三次CCF計算機軟件能力認證考試(2014年12月14日)的一道題目。小編今天有幸免費參加了此次考試。聽說這題是谷歌的筆試題變形??求證明。。html

好了,題外話不囉嗦,看題目java


題目

題目詳細以下:(來源自http://bbs.csdn.net/topics/390953265,好驚奇的帖子,不知道是哪位同窗在考試期間竟然能發帖到CSDN,讓我有幸複製到考試原文。此外http://www.0531s.com/content-53-1928772-1.html有轉發)算法


在圖像編碼的算法中,須要將一個給定的方形矩陣進行Z字形掃描(Zigzag Scan)。給定一個n×n的矩陣,Z字形掃描的過程以下圖所示:

  對於下面的4×4的矩陣,
  1 5 3 9
  3 7 5 6
  9 4 6 4
  7 3 1 3
  對其進行Z字形掃描後獲得長度爲16的序列:
  1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3
  請實現一個Z字形掃描的程序,給定一個n×n的矩陣,輸出對這個矩陣進行Z字形掃描的結果。
輸入格式
  輸入的第一行包含一個整數n,表示矩陣的大小。
  輸入的第二行到第n+1行每行包含n個正整數,由空格分隔,表示給定的矩陣。
輸出格式
  輸出一行,包含n×n個整數,由空格分隔,表示輸入的矩陣通過Z字形掃描後的結果。
樣例輸入
4
1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3
樣例輸出
1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3
評測用例規模與約定
  1≤n≤500,矩陣元素爲不超過1000的正整數。編程

------------------------------------------------------------------------------------------------------------------------------數組


分析

考完試回來上網搜了搜矩陣Z字形掃描,網上很多高手有先進的解法。這裏我就很少說了。你們能夠去百度或者谷歌。編碼


我在這裏分享下我考試時想到的比較直接的解法,略顯笨拙。記得題目給的運算時間和運行空間仍是比較寬鬆的。spa


在CCF認證考試的五道題裏面,該題排在第二的位置,顯然難度不是很大的,不宜戀戰,應當速戰速決。.net

考試當時想到的第一步就是看圖找規律。發現矩陣Z字形掃描從(0,0)位置開始,前進的方向有4個,分別是右、下,左下、右上。不難看出,Z字形掃描向右、向下兩個方向,只前進一步就會變向,改變後的方向因狀況而異;而左下和右上兩個方向則會一直延伸,直至前面沒法繼續直行時再變向爲向右或者向下。code

然而值得注意的時:htm

1.左下方向因沒法繼續直行須要變向時,要先判斷是否能往下走,若不能往下走再往右走;

2.右上方向因沒法繼續直行須要變向時,要先判斷是否能往右走,若不能往右走再往下走。

到這裏能夠總結出:下一步的方向,由上一步的方向以及周圍的狀況(是否臨界)決定。


想到這些,我就想模擬一我的在(0,0)這個位置出發,沿題目要求的路徑走到(n-1,n-1)的位置。因爲下一步的方向須要上一步的方向來參與決策,所以須要引入一個方向變量direction,分別用值1,2,3,4表明4個方向:右,下,左下,右上。編程的時候能夠分解爲兩個步驟: 

1.根據上一步的方向以及是否到達邊界位置來決定下一步方向;

2.根據步驟1獲得的方向前進一步,讀取該位置的數字。

循環直至到達終點(n-1, n-1)


說到這裏,相信看下面的代碼就能看懂了(爲了更容易看懂一些,有一部分代碼能夠簡化的沒有簡化)


代碼

(CCF認證考試對JAVA語言答題的要求:1.程序入口爲Main類的main方法;2.不能有package;3.輸入System.in,輸出System.out)

import java.util.Scanner;

public class Main {

	//下面四個變量表明四個方向
	public static final int RIGHT = 1;	//向右走
	public static final int DOWN = 2;	//向下走
	public static final int LEFTDOWN = 3;	//向作下走
	public static final int RIGHTUP = 4;	//向右上走
	
	public static int data[][];            //矩陣
	
	public static void main(String[] args) {
		new Main().run();
	}
	
	public static void run(){
		//接收輸入
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		data = new int[n][n];
		
		for(int i = 0; i < n; i++){
			for(int j = 0; j < n; j++){
				data[i][j] = scanner.nextInt();
			}
		}
		
		//從第一個位置開始,x爲橫座標,y爲縱座標,注意x,y在二維數組中的位置
		int x = 0;
		int y = 0;
		//輸出要求有空格隔開
		String result = data[y][x] + " ";
		//方向變量的初始值
		int direction = 0;	
		
		//下面就開始出發走咯
		while( !(x == n-1 && y == n-1) ){//循環直至到達終點(最右下角的位置)
			//先判斷下一步往哪一個方向走
			if(direction == 0){	//爲0說明還沒走出第一步,因此接着應該往右邊走一步
				direction = RIGHT;
			} else if(direction == RIGHT){ //上一次方向向右,下一步應該向左下或者右上
				if(x-1 >= 0 && y+1 < n){	//左下可走
					direction = LEFTDOWN;
				} else {	//只能走右上了
					direction = RIGHTUP;
				}
			} else if(direction == DOWN){	//上一次方向向下,下一步應該向左下或者右上
				if(x-1 >= 0 && y+1 < n){	//左下可走
					direction = LEFTDOWN;
				} else {	//只能走右上了
					direction = RIGHTUP;
				}
			} else if(direction == LEFTDOWN){	//上一次向左下,若是能夠,下一步應該繼續向左下,不然 向右或者向下走
				if(y+1 < n && x-1 >= 0){	//先判斷可否繼續向左下
					direction = LEFTDOWN;
				} else if(y+1 < n){	//而後判斷可否向下走
					direction = DOWN;
				} else {		//最後只能向右走了
					direction = RIGHT;
				}
			} else if(direction == RIGHTUP){	//上一次向右上,若是能夠,下一步應該繼續向右上,不然向右或者下走
				if(x+1 < n && y-1 >=0){	//先判斷可否繼續向右上
					direction = RIGHTUP;
				} else if(x+1 < n){	//而後判斷可否向右走
					direction = RIGHT;
				} else{			//最後只能向下走了
					direction = DOWN;
				}
			}
			
			//根據上面肯定的方向來走出下一步
			switch(direction){
				case RIGHT: x = x+1; break;
				case DOWN: y = y+1; break;
				case LEFTDOWN: x = x-1; y = y+1; break;
				case RIGHTUP: x = x+1; y = y-1; break;
			}
			
			//讀取當前走到位置的數字.注意x和y的位置
			result += data[y][x] + " ";
		}
		
		//輸出結果(這裏需不須要去掉最後的空格?沒怎麼玩過ACM,不記得了acc格式控制會不會這麼嚴)
		System.out.println(result);
	}

}


From:陳祖煌

Blog:http://my.oschina.net/chenzuhuang/blog

轉載必須說明出處

--------------------------------------------------------------------------------------

相關文章
相關標籤/搜索