Matlab小練習:按斜線方向依次賦值矩陣
來自知乎問題,覺得挺有意思,留給學生解答之餘,我也做了一番思考,得到三種解法。
題目如下:
以n=80為例,
————————————————————
一、先要根據 確定矩陣的階數
如果先生成足夠大矩陣,再刪掉全為零的列,有點太low了。所以先思考一個演算法:
觀察數據放置的特點,不難發現這樣一個關係:
變形:
觀察,若 足夠大, 起決定作用, 取整一定是
較小的 (或 ) 對嗎?試一試。
測試 至 :
n=1:56;round(sqrt(2*n))
剛好是對的!
二、將 按斜線依次放置
無非是找到放置規律放數而已,放置就是用行標列標賦值,所以就是找行標、列標規律。
先寫個數的方便觀察規律,比如,
方法一. 行標、列標分別找規律
依次賦值的
行標: 共 組 個數
列標: 共 組 個數
(因為是 條斜線)
既然如此,按上述規律生成(拼接)行標、列標,再賦值即可。
編寫函數:
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)
方法二. 行標列標一起找規律
依次賦值的
行標和列標:
先是「和為 」的,再「和為 」的,再「和為 」的,……; 每個子組裡面又是行標從小到大排列。
因此,先生成所有行標列標組合( 與 的笛卡爾積),第一關鍵字按"行標列標之和"排序,再第二關鍵字按行標排序,排好序的取出前 個,依次賦值 即可。
編寫函數:
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;
測試函數(略)
方法三. 用循環語句實現
用循環語句控制行標、列標按該規律出現,依次賦值:
編寫函數:
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
注意,外層循環用 控制依次從第 列到第 列起始的斜線;對每條斜線,先循環 ,從 到 ;而始終有 .
測試函數(略)
三、稍微提升一下
只賦值 , 實用性不大,如果改進一下,對給定的一個向量 , 將 中的值依次按斜線方向賦值成矩陣呢?
非常簡單,參數由 換成向量 , 則 的長度即為需要的 ,再將最後賦值時用的 換成 即可。
改進的第一個函數:
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圖像處理中的小波變換