1. 程式人生 > >CCF 201412-2 Z字形掃描 JAVA實現

CCF 201412-2 Z字形掃描 JAVA實現

問題描述   在影象編碼的演算法中,需要將一個給定的方形矩陣進行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字形掃描的時候什麼進行下一“斜行”的掃描,比如遇到矩陣邊界的時候進入下一“斜行”,但進入下一“斜行”有水平、有向下的方向,這樣整個過程需要做出很多繁雜的判斷,這裡我介紹一種比較簡單巧妙的方法! 我們可以發現,每條“斜行”上的元素,其行座標和列座標加起來的和是相同的,且每條“斜線”上的和依次從0遞增到2*(n-1),n為矩陣行數,比如樣例輸入中1元素的座標為[0,0],行、列座標和為0,“斜線”上元素5和3座標分別為[0,1]和[1,0],行列座標和為1,元素3、7、9行列座標和為2.。。。。。。以此類推。所以我們將行列座標和相同的元素存到同一列裡面,如下所示,按照輸入順序將元素存到每一列中,i+j表示行列座標和,作為每一列的索引:


只要我們根據題意交替按反序和正序遍歷每一列,所遍歷的結果即為Z字形掃描的結果。具體程式碼如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class _12_02_other {
	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		boolean mark=true;//用來標記交替正反遍歷每一列
		int n=scanner.nextInt();
		T[]S=new T[2*n-1];//n*n矩陣行列座標和從0到2*(n-1),故定義的列數為2*n-1
		for(int i=0;i<=2*n-2;i++){
			S[i]=new T();
		}
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				//行列和相同的存放同一列中
				S[i+j].add(scanner.nextInt());
			}
		}
		/*
		 * 遍歷每一列
		 */
		for(int i=0;i<S.length;i++){
			if(mark){
				S[i].outReverse();
				mark=!mark;
			}else {
				S[i].outForward();
				mark=!mark;
			}
		}
		scanner.close();
	}
}
class T{
	private List<Integer> L;//用來儲存每一列元素
	public T(){
		L=new ArrayList<>();
	}
	public void add(int a){
		L.add(a);
	}
	public void outForward(){//正序遍歷
		for(int b:L){
			System.out.print(b+" ");
		}
	}
	public void outReverse(){//反序遍歷
		for(int i=L.size()-1;i>=0;i--){
			System.out.print(L.get(i)+" ");
		}
	}
}