一个 minizinc 函数,用于检查 n*n 矩阵中每个元素的邻居

问题描述

我正在尝试在 minizinc 中搜索 n*n 矩阵的元素的每个邻居。到目前为止,我以非常有效的方式使用了整个矩阵的 if-else 和单独的条件来处理边界变量。我对 minizinc 有点陌生,我希望是否有一种有效的方法来做到这一点。可能有函数什么的。

    int: size; % Enter the size lads
 

set of int: board  = 0..size-1;


array[board,board] of var 0..1: grid;   
 
var int: z = sum(r in board,c in board) (grid[r,c]);

% solve maximize z;
solve :: int_search(
        [grid[i,j] | i,j in board],smallest,indomain_max,complete)
    maximize z;
 
constraint
  

  forall(r in board,c in board,x in board) (       
        if (r==0/\c==0) then           %corner 1
                      (
                           
                           if ( (grid[r,c+1] + grid[r+1,c+1]+grid[r,c+1])==3) then (grid[r,c] = 1)
                             
                              elseif(
                            (grid[r,c+1])  ==2)then(grid[r,c] = grid[r,c]) 
                            
                           else grid[r,c]=0 endif
                     )
                            
                            
       elseif (r==size-1/\c==size-1) then   %corner2
          (  if ((grid[r-1,c]+grid[r,c-1]+grid[r-1,c-1])==3) then  (grid[r,c] = 1)    
                         
            elseif((grid[r-1,c-1]) ==2) then (grid[r,c]) 
                          
            else (grid[r,c] = 0)   endif
           )                
       elseif (r==0/\c==size-1) then           %corner3
          (  if( (grid[r,c-1]+grid[r+1,c]+grid[r+1,c-1])==3) then (grid[r,c] = 1)   
           
             elseif((grid[r,c-1]) ==2)then (grid[r,c]) 
             else(grid[r,c] = 0)   endif
          )         
      elseif (r==size-1/\c==0)   then   %corner4
          (  if((grid[r-1,c+1]+grid[r-1,c] = 1)                  
             elseif((grid[r-1,c+1]) ==2) then  (grid[r,c] = 0)   endif
           )              
     elseif (r==0/\c==x/\c!=0/\c!=size-1) then   %top row
          (  if((grid[r,c] = 1)                   
                         
             elseif((grid[r,c+1])==2 ) then (grid[r,c])   
             else(grid[r,c] = 0)   endif
           )              
     elseif (r==size-1/\c==x/\c!=0/\c!=size-1) then   %last row
          (  if((grid[r,c]+grid[r-1,c] = 1)     
             elseif((grid[r,c+1]) ==2 ) then (grid[r,c] = 0)  endif 
           )              
     elseif (r==x/\c==0/\r!=0/\r!=size-1) then   %first col
          (  if ((grid[r-1,c+1]+grid[r+1,c])==3) then (grid[r,c] = 1)   
             elseif((grid[r-1,c]) ==2) then (grid[r,c])    
             else (grid[r,c] = 0)  endif 
          )   
     
     elseif (r==x/\c==0/\r!=0/\r!=size-1) then   %last col
           ( if((grid[r-1,c-1]+grid[r,c] = 1)                 
             elseif((grid[r-1,c]) ==2)then(grid[r,c] = 0)   endif
           )              
       elseif (r!=0 /\ c!=x) /\ (r!=size-1/\c!=x)/\(r!=x/\c!=0)/\(r!=x/\c!=size-1) then  %rest
             (if(( grid[r-1,c-1] + grid[r-1,c] + grid[r-1,c+1] +
                          grid[r,c-1] + grid[r,c+1] +
                          grid[r+1,c-1] + grid[r+1,c] + grid[r+1,c+1]
                          )==3)then(grid[r,c] = 1)   
                   
               elseif  (( grid[r-1,c+1]
                          )==2 )then (grid[r,c])
                 
               else(grid[r,c] = 0)   
              endif
              ) /\       %endif  
      if (grid[r,0]==1 /\ grid[r+1,0]==1) then grid[r+2,0]=0 endif /\
   if (grid[0,c]==1 /\ grid[0,c+1]==1) then grid[0,c+2]=0 endif /\
   if (grid[size-1,c]==1 /\ grid[size-1,c+1]==1) then grid[size-1,c+2]=0 endif /\
   if (grid[r,size-1]==1 /\ grid[r+1,size-1]==1) then grid[r+2,size-1]=0 endif          
      else r=r/\c=c    
   endif             
   
  )
  /\
  forall(r in board,c in board)(
   if (grid[r,0]=0 endif /\
  if (grid[0,c+2]=0 endif /\
   if (grid[size,c]==1 /\ grid[size,c+1]==1/\ c<size-2/\c>1) then grid[size-1,size]==1 /\ grid[r+1,size]==1 /\ r<size-2/\r>1) then grid[r+2,size-1]=0 endif
  )

;
 
output [
  if j = 0 then "\n" else " " endif ++
   show(grid[i,j])
  | i,j in board
]
;

解决方法

这是对单元格的邻居求和的一般方法(不包括“这个”单元格)。对于每个单元格,它定义了一个临时变量 (t),用于对相邻单元格的值求和。然后,您必须为 t 的不同值添加逻辑。

int: r = 4; % rows
int: c = 4; % column

array[1..r,1..c] of var 0..1: x;

constraint
    forall(i in 1..r,j in 1..c) ( 
        let {
          var 0..r*c: t
      }
      in
       t = sum(a,b in {-1,1} where 
            i+a in 1..r  /\ j+b in 1..c % ensure we are in the matrix
             /\ (a != 0 \/ b != 0) % don't include "this" cell
            ) (x[i+a,j+b])
    )
;

solve satisfy;

更新:这是带有函数 sum_neighbors 的相同模型,用于计算特定单元格的邻居数。

int: r = 4; % rows
int: c = 4; % column

array[1..r,1..c] of var 0..1: x;

function var int: sum_neighbors(int: i,int: j) =
   sum(a,1} where 
         i+a in 1..r  /\ j+b in 1..c /\ (a != 0 \/ b != 0)
        ) (x[i+a,j+b])

;


constraint
forall(i in 1..r,j in 1..c) (
        let {
          var 0..r*c: t
      }
      in
       t = sum_neighbors(r,c)
    )
;
solve satisfy;

您不必使用临时 t 变量,我添加它只是为了能够测试模型。你现在可以写像

这样的东西
constraint
forall(i in 1..r,j in 1..c) (
        if sum_neighbors(r,c) == 2 then
          % ...
        else
          % ...
        endif
    )
;