- 积分
- 83
- 注册时间
- 2003-11-14
- 仿真币
-
- 最后登录
- 1970-1-1
|
楼主 |
发表于 2013-5-13 19:04:20
|
显示全部楼层
来自 新疆乌鲁木齐
本帖最后由 bainhome 于 2013-5-13 20:04 编辑
以上各位基础数据操作都用得相当精妙,其中两个求解基本是我个人心目中的leading solution,佩服。
出这道题有我自己的意图:这题解法非常之多,总结起来有两种大致思路:
1.利用MATLAB现有的特殊矩阵和测试矩阵,用built-in命令实现再构造;
2.老老实实循环,不管是几重,不管用不用各种arrayfun、bsxfun,或者就是for。
思路1中有如下几个比较好的思路:
1).“托普利茨”常对角阵打底,用其他基础矩阵操作旋转、相加等完成计算例如:- >> c = toeplitz(1:5)
- c =
- 1 2 3 4 5
- 2 1 2 3 4
- 3 2 1 2 3
- 4 3 2 1 2
- 5 4 3 2 1
- >> c = (c + fliplr(c))/2
- c =
- 3 3 3 3 3
- 3 2 2 2 3
- 3 2 1 2 3
- 3 2 2 2 3
- 3 3 3 3 3
复制代码 2).托普利茨阵与rot90旋转阵的组合:- >> n=5;c=toeplitz(1:n)/2
- c =
- 0.5000 1.0000 1.5000 2.0000 2.5000
- 1.0000 0.5000 1.0000 1.5000 2.0000
- 1.5000 1.0000 0.5000 1.0000 1.5000
- 2.0000 1.5000 1.0000 0.5000 1.0000
- 2.5000 2.0000 1.5000 1.0000 0.5000
- >> c + rot90(c)
- ans =
- 3 3 3 3 3
- 3 2 2 2 3
- 3 2 1 2 3
- 3 2 2 2 3
- 3 3 3 3 3
复制代码 3).使用螺旋阵spiral构造,这也是现在cody上真正的leading solution核心流程。- c=spiral(n)
- c =
- 21 22 23 24 25
- 20 7 8 9 10
- 19 6 1 2 11
- 18 5 4 3 12
- 17 16 15 14 13
- c=sqrt(c)
- c =
- 4.5826 4.6904 4.7958 4.8990 5.0000
- 4.4721 2.6458 2.8284 3.0000 3.1623
- 4.3589 2.4495 1.0000 1.4142 3.3166
- 4.2426 2.2361 2.0000 1.7321 3.4641
- 4.1231 4.0000 3.8730 3.7417 3.6056
- c=0.5+0.5*c
- c =
- 2.7913 2.8452 2.8979 2.9495 3.0000
- 2.7361 1.8229 1.9142 2.0000 2.0811
- 2.6794 1.7247 1.0000 1.2071 2.1583
- 2.6213 1.6180 1.5000 1.3660 2.2321
- 2.5616 2.5000 2.4365 2.3708 2.3028
- c=ceil(c)
- c =
- 3 3 3 3 3
- 3 2 2 2 3
- 3 2 1 2 3
- 3 2 2 2 3
- 3 3 3 3 3
复制代码 4).mahatton权重距离阵做法:- 0.5*(mandist(1:n)+flipud(mandist(1:n)))+1;
复制代码 5).boxdist函数:- function a = bullseye(n)
- a = diag([(n+1)/2:-1:1 2:(n+1)/2]);
- a = boxdist(a)+a;
- end
复制代码 当然还有人用nwcwww所给的图像处理函数的做法,他们基本都是属于第1中思路,即利用特殊矩阵做底阵,然后通过一些矩阵基础操作,或凑或算,达到计算目的
(3)是size最小的leading solution的思想,但这种做法有些取巧,其实那个size最小的用了动态正则替换,把原本18的size降到了11,我认为这种无厘头做法,纯粹属于偏执,不值得提倡,可是人家的正则替换用得真心是牛A<X<牛C,这也不得不承认:- regexp('','(?@y=ceil(sqrt(spiral(n))/2+0.5);)');
复制代码 另一种思路最实在,也被很多MATLAB learner很看不起——循环:
1).- for i = 0 : n / 2
- j = i + 1 : n - i;
- a( j, j ) = ( n + 1 ) / 2 - i;
- end
复制代码 2).当然这种做法也有很多变体,比如liuyalong给的:- for i=0:(1+n)/2-1
- a([(1+n)/2-i,(1+n)/2+i],[(1+n)/2-i:(1+n)/2+i])=i+1;
- a([(1+n)/2-i:(1+n)/2+i],[(1+n)/2-i,(1+n)/2+i])=i+1;
- end
复制代码 3).- n1=(n+1)/2;
- a=n1*ones(n);
- x=[n1,1,length(a)];
- for i=n1-1:-1:1
- a(x(2)+1:x(3)-1,x(2)+1:x(3)-1)=(x(1)-1)*ones(2*i-1);
- x=[x(1)-1,x(2)+1,x(3)-1];
- end
复制代码 上面这个思路和lin2009提供的思想有些许类似。
4).递归计算:- function a = bullseye(n)
- try
- a = ones(n)*ceil(n/2);
- a(2:end-1,2:end-1) = bullseye(n-2);
- end
- end
复制代码 还有一种思路介于二者之间,无论bsxfun这种逐元素操作还是meshgrid(ndgrid)布点再用max做逻辑判断都属于这种,动作分解如下:- c=meshgrid(1:n)
- c =
- 1 2 3 4 5
- 1 2 3 4 5
- 1 2 3 4 5
- 1 2 3 4 5
- 1 2 3 4 5
复制代码- c=c-(n+1)/2
- c =
- -2 -1 0 1 2
- -2 -1 0 1 2
- -2 -1 0 1 2
- -2 -1 0 1 2
- -2 -1 0 1 2
复制代码- c=abs(c)
- c =
- 2 1 0 1 2
- 2 1 0 1 2
- 2 1 0 1 2
- 2 1 0 1 2
- 2 1 0 1 2
复制代码- c=max(c,c')
- c =
- 2 2 2 2 2
- 2 1 1 1 2
- 2 1 0 1 2
- 2 1 1 1 2
- 2 2 2 2 2
复制代码- c=c+1
- c =
- 3 3 3 3 3
- 3 2 2 2 3
- 3 2 1 2 3
- 3 2 2 2 3
- 3 3 3 3 3
复制代码 bxcfun变体,实际和前面一个道理:
- b=[0.5*n+0.5:-1:1 2:0.5*n+0.5]
- a=bsxfun(@max,b,b')
复制代码 点评:这两种思路(最后meshgrid+max的做法其实是属于第1种)难说优劣,多数MATLAB Fans偏重于前一种:想必长泡论坛很多用循环写代码的伙计都不好意思在论坛里公开用循环解决问题,怕遭人笑,实在没法避免也要用arrayfun包装一下,以前我也有这种想法,而且很严重...
前两天某论坛里又有个关于90%循环在MATLAB中是否可以避免的争执(也算争执),我感觉MATLAB代码写得成矢量化固然是功力的体现,可循环这种东西现在一来效率不算低,当然我承认也有较极端的例子反向说明这个观点的绝对和武断,可实际问题求解中有几个问题要循环到10w次以上?吴鹏这种整天跟卫星高清图片过不去的变态鸟人除外。所以我觉得没事for两下也没啥大不了;二来还有一个比较实际的好处:写代码写得老实,该for就for,这样的代码容易看懂、移植性好,前面那个循环的办法size=38,高于leading solution整整27个,但是如果改成C#代码,用5min稍微调一下语法,搞定!至于那个飘逸潇洒的leading solution估计就头疼了。毕竟有几个人喜欢整天带着MCRinstaller到处跑的?现在好多人吭哧吭哧改MATLAB算法为其他语言,都被爽得痛不欲生,矢量化是其中一原因。所以前天我跟祁彬彬qq开玩笑说那个用for写bullseye的兄弟是个实在人,呵呵。不过事先也说好:别较劲,跟我说“你既然这么强调底层,干脆把啥东西都往二进制上写!”
悄悄告诉你:我真想写,可惜水平没你奇葩...
个人观点+一点闲话,大家听听就好,我是答应lengyunfeng写点儿东西捧场。各位水准都很高,simwe虽如今阵容不齐,可如此残阵依旧猛男云集,水底下藏的都是大鱼。这样的问题放在其他论坛估计参与的不会多(祁彬彬试过,压根儿没人搭理这厮,那天结贴的时候写那么长,我估计是看到大家突然搭理,热泪盈眶一时之间没想开,就难得地总结了那多玩意儿,哈哈)。建议兄弟们cody上转转吧!除了lin2009是多软件混成部队,nwcwww和liuyalong你俩明明能玩儿大江大海,还赖在游泳池浅水区里带着救生圈猛练狗刨? |
评分
-
2
查看全部评分
-
|