Fortran Coder

查看: 16648|回复: 11
打印 上一主题 下一主题

[通用算法] 计算二维数组坐标“岛”的重心问题

[复制链接]

17

帖子

4

主题

0

精华

入门

F 币
80 元
贡献
50 点
跳转到指定楼层
楼主
发表于 2014-3-6 13:34:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我刚接触fortran没多久,现在要写一个程序来算出下面这个数组的重心
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

我想把这个数组其中所有的1的值用坐标表示出来,比如(14,15)这样子,但是我不太清楚该怎么筛选和表示,求大神指点
分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

742

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
726 元
贡献
371 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

沙发
发表于 2014-3-6 13:37:33 | 只看该作者
[Fortran] 纯文本查看 复制代码
1Do i = 1 , n
2  Do j = 1 , m
3    if ( a(i,j) == 1 ) then
4      !此时的 i j 即为坐标
5    end if
6  End Do
7End Do

17

帖子

4

主题

0

精华

入门

F 币
80 元
贡献
50 点
板凳
 楼主| 发表于 2014-3-6 13:43:38 | 只看该作者
chuxf 发表于 2014-3-6 13:37
[mw_shl_code=fortran,true]Do i = 1 , n
  Do j = 1 , m
    if ( a(i,j) == 1 ) then

0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0
如果是这样的,我想用程序判断上面的那些1把他们-20变到下面来该怎么做呢?

742

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
726 元
贡献
371 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

地板
发表于 2014-3-6 13:45:19 | 只看该作者
什么叫 把他们 -20 变到下面来?

17

帖子

4

主题

0

精华

入门

F 币
80 元
贡献
50 点
5#
 楼主| 发表于 2014-3-6 13:55:14 | 只看该作者
chuxf 发表于 2014-3-6 13:45
什么叫 把他们 -20 变到下面来?

如果把所有的1看成一个岛,我想算这个岛重心,我想把所有的1的坐标全部相加最后除以25就是这个岛的重心,但是这是一个周期性的岛,就像第二组数组,有一部分1在上面,比如(5,20),但实际这个1是该在(5,0)这个坐标上,但是因为下面无法表示了所以这个1就被加了20跑到上面去了,但在计算重心的时候需要把这个1减掉20,就是从(5,20)变到(5,0)来计算重心

742

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
726 元
贡献
371 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

6#
发表于 2014-3-6 14:07:32 | 只看该作者
本帖最后由 chuxf 于 2014-3-6 14:15 编辑

这个问题可以很简单,也可以很复杂。

这取决于:
第一:整个区域内,你是否可以确定只存在一个“岛”?还是有可能有多个?
比如:
00000000000001111111100000000000
00000000000000011110000000000000
00000000000000000000000000000000
00000000110000000000000000000000
00000001111000000000000000000000
00000000000000000000000000000000
第二:岛会不会出现无限循环。
比如:
00000000000001111000000000000000
00000000000001111000000000000000
00000000001111111000000000000000
00000000000001111000000000000000
第三:岛中间是否可能出现空洞?
比如:
00000000000000000000000000000000
00000000000001111000000000000000
00000000000001111000000000000000
00000000001111001000000000000000
00000000000001111000000000000000
00000000000000000000000000000000

17

帖子

4

主题

0

精华

入门

F 币
80 元
贡献
50 点
7#
 楼主| 发表于 2014-3-6 14:26:03 | 只看该作者
chuxf 发表于 2014-3-6 14:07
这个问题可以很简单,也可以很复杂。

这取决于:

只有一个岛,就是加了周期或者减了周期后就只有一个岛了,不会有2个,岛中间没有空洞,无限循环那个不太懂。

742

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
726 元
贡献
371 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

8#
发表于 2014-3-6 15:24:54 | 只看该作者
本帖最后由 chuxf 于 2014-3-6 19:22 编辑

我这里有个死办法,那就是如果有上下左右的联通,则移动整个区域,直到不再联通为止。(记录下 X Y 的偏移量)
最后算出重心,再把偏移量加回去。

[Fortran] 纯文本查看 复制代码
001Program www_fcode_cn
002  Implicit None
003  Integer , parameter :: N = 4
004  Integer , parameter :: M = 4
005  real :: gx , gy
006  Integer :: a( M , N )
007  Open( 12 , File = '文件名' )
008  Read( 12 , * ) a
009  Close( 12 )
010  call IslandGravity( a , N , M , gx , gy )
011  write(*,*) gx , gy
012  
013contains
014 
015  Subroutine IslandGravity( d , n , m , gx , gy )
016    Integer :: n , m
017    Integer :: d( m , n ) , a( m , n )
018    integer :: i , j , c , iShiftX , iShiftY
019    Real :: gx , gy
020    Logical :: blink
021    a = d !// 复制一份 a
022 
023    iShiftX = 0
024    iShiftY = 0
025    Do  !// 向上滚动,直到没有上下链接为止
026      blink = Check_Y_Link( a , n , m )
027      if ( blink ) then
028        call RollUp( a , n , m )
029        iShiftY = iShiftY + 1
030      else
031        Exit
032      end if
033    End Do
034    Do  !// 向左滚动,直到没有左右链接为止
035      blink = Check_X_Link( a , n , m )
036      if ( blink ) then
037        call RollLeft( a , n , m )
038        iShiftX = iShiftX + 1
039      else
040        Exit
041      end if
042    End Do
043    gx = 0.
044    gy = 0.
045    c = 0
046    Do i = 1 , N
047      Do j = 1 , M
048        if ( a(j,i) == 1 ) then
049          gx = gx + j
050          gy = gy + i
051          c = c + 1
052        end if
053      End Do
054    End Do
055    gx = ( gx / c ) + iShiftX !// 最后再把偏移量加上去
056    if ( gx > m ) gx = gx - m
057    gy = ( gy / c ) + iShiftY
058    if ( gy > n ) gy = gy - n
059  End Subroutine IslandGravity
060   
061  Subroutine RollUp( a , n , m ) !// 区域向上滚动
062    Integer :: n , m
063    Integer :: a( m , n ) , t( m )
064    t(:) = a( : , 1 )
065    a(:,1:n-1) = a(:,2:n)
066    a(:,n) = t(:)
067  End Subroutine RollUp
068   
069  Subroutine RollLeft( a , n , m ) !// 区域向左滚动
070    Integer :: n , m
071    Integer :: a( m , n ) , t( n )
072    t(:) = a( 1 , : )
073    a(1:m-1,:) = a(2:m,:)
074    a(m,:) = t(:)
075  End Subroutine RollLeft
076   
077  Logical Function Check_Y_Link( a , n , m ) !// 检查是否有上下链接
078    Integer :: n , m
079    Integer :: a( m , n )
080    integer :: i
081    Check_Y_Link = .false.
082    Do i = 1 , m
083      if ( ( a(i,1) == 1 ) .and. ( a(i,n) == 1 ) ) then
084        Check_Y_Link = .true.
085        return
086      end if
087    End Do
088  End Function Check_Y_Link
089   
090  Logical Function Check_X_Link( a , n , m ) !// 检查是否有左右链接
091    Integer :: n , m
092    Integer :: a( m , n )
093    integer :: i
094    Check_X_Link = .false.
095    Do i = 1 , n
096      if ( ( a(1,i) == 1 ) .and. ( a(m,i) == 1 ) ) then
097        Check_X_Link = .true.
098        return
099      end if
100    End Do
101  End Function Check_X_Link
102   
103End Program www_fcode_cn

3

帖子

1

主题

0

精华

新人

F 币
27 元
贡献
13 点
9#
发表于 2014-3-6 19:01:55 | 只看该作者
不清楚这里重心的意义为何,感觉有一点点问题:
例如:
1101
1101
0000
1101
重心按个人理解应该是1即坐标(1,1),算出来的结果应该是(5,5),超出了范围。

742

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
726 元
贡献
371 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

10#
发表于 2014-3-6 19:23:39 | 只看该作者
joejimming 发表于 2014-3-6 19:01
不清楚这里重心的意义为何,感觉有一点点问题:
例如:
1101

感谢楼上指正。

已增加两行代码解决这一问题

[Fortran] 纯文本查看 复制代码
1gx = ( gx / c ) + iShiftX !// 最后再把偏移量加上去
2if ( gx > m ) gx = gx - m
3gy = ( gy / c ) + iShiftY
4 if ( gy > n ) gy = gy - n
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2025-4-30 01:58

Powered by Discuz! X3.4

© 2013-2025 Comsenz Inc.

快速回复 返回顶部 返回列表