PAT(乙級) 1050 螺旋矩陣

本題要求將給定的 N 個正整數按非遞增的順序,填入“螺旋矩陣”。所謂“螺旋矩陣”,是指從左上角第 1 個格子開始,按順時針螺旋方向填充。要求矩陣的規模爲 m 行 n 列,滿足條件:m×n 等於 N;m≥n;且 m−n 取所有可能值中的最小值。

輸入格式:

輸入在第 1 行中給出一個正整數 N,第 2 行給出 N 個待填充的正整數。所有數字不超過 10​4​​,相鄰數字以空格分隔。

輸出格式:

輸出螺旋矩陣。每行 n 個數字,共 m 行。相鄰數字以 1 個空格分隔,行末不得有多餘空格。

輸入樣例:

12
37 76 20 98 76 42 53 95 60 81 58 93

輸出樣例:

98 95 93
42 37 81
53 20 76
58 60 76

 

        本題是要按螺旋的順序來爲一個空二維矩陣的每個位置填充數字,與這種規律類似的還有Z字型填充,就像下圖這樣:

        這種題我總結了一種通用做法,就是假設有一個指針在指引着填充數字的位置,然後找出這個指針的所有運動方向。在本題中這個指針有四個運動方向,即上下左右,不同狀態下矩陣的兩個下標的變化不同。假設這個二維矩陣的兩個下標爲i和j。則分析螺旋的四種狀態下的變化:

        上:在同一列運動,j不變,i減1。若走到頭則轉爲右

        下:在同一列運動,j不變,i加1。若走到頭則轉爲左

        左:在同一行運動,i不變,j減1。若走到頭則轉爲下

        右:在同一行運動,i不變,j加1。若走到頭則轉爲上

        走到頭包括兩種情況,一種是到了矩陣的邊界,再前進則越界,另一種是下一個位置已經有數字了。走到頭後就應該變換前進方向。找出運動的規律之後依次填入數字,代碼如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int N;
	cin>>N;
	int num[N];
	for(int i=0;i<N;i++)
		scanf("%d",&num[i]);
	sort(num,num+N);
	int n=(int)sqrt(N),m;//計算矩陣的行和列
	while(N%n!=0)
		n--;
	m=N/n;
	int res[m][n],i=0,j=0,flag=1;//i和j代表下標,flag表示前進方向
	memset(res,0,sizeof(res));
	for(int k=N-1;k>=0;k--)//要以非遞增順序填充,則排序後倒着遍歷
	{
		if(flag==1)//向右
		{
			res[i][j]=num[k];
			j++;
			if(j==n || res[i][j]!=0)//走到頭要轉爲向下,因爲此時的下標是越界的,所以要糾正
			{
				j--;
				i++;
				flag=2;
			}
		}
		else if(flag==2)//向下
		{
			res[i][j]=num[k];
			i++;
			if(i==m || res[i][j]!=0)//轉爲向左,並糾正座標
			{
				j--;
				i--;
				flag=3;
			}
		}
		else if(flag==3)//向左
		{
			res[i][j]=num[k];
			j--;
			if(j==-1 || res[i][j]!=0)//轉爲向上,糾正座標
			{
				j++;
				i--;
				flag=4;
			}
		}
		else//向上
		{
			res[i][j]=num[k];
			i--;
			if(i==-1 || res[i][j]!=0)//轉爲向右,糾正座標
			{
				i++;
				j++;
				flag=1;
			}
		}
	}
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
		{
			cout<<res[i][j];
			if(j!=n-1)
				cout<<" ";
		}
		cout<<endl;
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章