Matlab小練習:按斜線方向依次賦值矩陣

來自知乎問題,覺得挺有意思,留給學生解答之餘,我也做了一番思考,得到三種解法。

題目如下:

以n=80為例,

————————————————————

一、先要根據 n 確定矩陣的階數 k

如果先生成足夠大矩陣,再刪掉全為零的列,有點太low了。所以先思考一個演算法:

觀察數據放置的特點,不難發現這樣一個關係:

frac{k(k-1)}{2} < n leq frac{k(k+1)}{2}

變形:

k^2-k < 2n leq k^2+k

觀察,若 k 足夠大, k^2 起決定作用, sqrt{2n} 取整一定是 k

較小的 k (或 n ) 對嗎?試一試。

測試 n=156 :

n=1:56;round(sqrt(2*n))

剛好是對的!

二、將 1 sim n 按斜線依次放置

無非是找到放置規律放數而已,放置就是用行標列標賦值,所以就是找行標、列標規律。

先寫個數的方便觀察規律,比如, n=20

方法一. 行標、列標分別找規律

1 sim n 依次賦值的

行標: 1; ~1,2; ~1,2,3; ~1,2,3,4; ~1,cdotskn 個數

列標: 1; ~2,1;~ 3,2,1; ~4,3,2,1; ~5, cdotskn 個數

(因為是 k 條斜線)

既然如此,按上述規律生成(拼接)行標、列標,再賦值即可。

編寫函數:

function A=DiagNum1(n)k=round(sqrt(2*n)); %確定矩陣階數kA=zeros(k);%% 生成行標, 列標I=[];J=[];for i=1:k I=[I,1:i]; J=[J,i:-1:1];endIND=sub2ind(size(A),I,J); %二維索引轉化為一維索引A(IND(1:n))=1:n;

注意,生成行標列標索引後,[I, J]作為二維索引值,是不能直接用A([I,J])=1:n來賦值的,故做了二維索引到一維索引的轉化。

測試函數:

DiagNum1(80)

方法二. 行標列標一起找規律

1 sim n 依次賦值的

行標和列標: (1,1); ~(1,2), (2,1); ~(1,3), (2,2), (3,1); ~(1,4), (2,3), cdots

先是「和為 2 」的,再「和為 3 」的,再「和為 4 」的,……; 每個子組裡面又是行標從小到大排列。

因此,先生成所有行標列標組合( 1sim n1 sim n 的笛卡爾積),第一關鍵字按"行標列標之和"排序,再第二關鍵字按行標排序,排好序的取出前 n 個,依次賦值 1sim n 即可。

編寫函數:

function A=DiagNum2(n)k=round(sqrt(2*n)); %確定矩陣階數kA=zeros(k);%% 生成所有下標組合(笛卡爾積)[X,Y]=meshgrid(1:n,1:n);subn=[X(:),Y(:)];%% 選取索引並賦值ind=sortrows([subn,sum(subn,2)],3); %對下標求和, 按該和排序, 已經滿足要求IND=sub2ind(size(A), ind(1:n,1),ind(1:n,2)); %選出前n個二維索引, 並轉化為一維A(IND)=1:n;

測試函數(略)

方法三. 用循環語句實現

用循環語句控制行標、列標按該規律出現,依次賦值:

(1,1) quad k=1 quad i=1 quad j=1 \ (1,2) quad k=2 quad i=1 quad j=2 \ (2,1) quad k=2 quad i=2 quad j=1 \ (1,3) quad k=3 quad i=1 quad j=3 \ (2,2) quad k=3 quad i=2 quad j=2 \ (3,1) quad k=3 quad i=3 quad j=1 \ cdots cdots

編寫函數:

function A=DiagNum3(n)k=round(sqrt(2*n)); %確定矩陣階數kA=zeros(k);val=1;for m=1:k for i=1:m A(i,m+1-i)=val; val=val+1; if val>n break; end endend

注意,外層循環用 m 控制依次從第 1 列到第 k 列起始的斜線;對每條斜線,先循環 i ,從 1m ;而始終有 i+j=m+1 .

測試函數(略)

三、稍微提升一下

只賦值 1 sim n , 實用性不大,如果改進一下,對給定的一個向量 V , 將 V 中的值依次按斜線方向賦值成矩陣呢?

非常簡單,參數由 n 換成向量 V , 則 V 的長度即為需要的 n ,再將最後賦值時用的 1:n 換成 V 即可。

改進的第一個函數:

function A=DiagNum1(V)n=length(V);k=round(sqrt(2*n)); %確定矩陣階數kA=zeros(k);%% 生成行標, 列標I=[];J=[];for i=1:k I=[I,1:i]; J=[J,i:-1:1];endIND=sub2ind(size(A),I,J); %二維索引轉化為一維索引A(IND(1:n))=V;

改進的第二個函數:

function A=DiagNum2(V)n=length(V);k=round(sqrt(2*n)); %確定矩陣階數kA=zeros(k);%% 生成所有下標組合(笛卡爾積)[X,Y]=meshgrid(1:n,1:n);subn=[X(:),Y(:)];%% 選取索引並賦值ind=sortrows([subn,sum(subn,2)],3); %對下標求和, 按該和排序IND=sub2ind(size(A), ind(1:n,1),ind(1:n,2)); %選出前n個二維索引, 並轉化為一維A(IND)=V;

改進的第三個函數(稍有不同):

function A=DiagNum3(V)n=length(V);k=round(sqrt(2*n)); %確定矩陣階數kA=zeros(k);val=1;for m=1:k for i=1:m A(i,m+1-i)=V(val); val=val+1; if val>n break; end endend

若還要得到原問題的結果,只需這樣調用函數即可:

DiagNum1(1:n)DiagNum2(1:n)DiagNum3(1:n)

原創文章,轉載請註明。

推薦閱讀:

[matDL框架開發直播:2]全連接層(dense)的實現和優化
Python和MATLAB交互的基本操作
MATLAB圖像處理中的小波變換

TAG:MATLAB | 矩阵 | 函数 |