Sayfalar

19 Mart 2017

Euler Projesi 215. Soru

Çatlak Bulunmayan Duvar

 2x1 ve 3x1 (yatayxdikey) boyutlu tuğlalardan daha güçlü olması için herhangi bir sıradaki tuğlalar arası boşluk ile alt yada üst sıradaki boşlukların çakışmadığı (çakışması durumuna "sürekli çatlak" denir) bir duvar örülecek.

Örneğin, aşağıdaki 9x3 duvar kırmızı ile gösterilen sürekli çatlaktan dolayı kabul edilemez.

"Sürekli çatlak" bulunmayan 9x3 boyutunda 8 farklı duvar yapımı mümkündür. Bunu W(9,3)=8 ile gösterelim.
Bu durumda W(32,10) değeri kaçtır?

Cevap:  806844323190414
C++:
#include <stdio.h>
#include <stdlib.h>

#define height 10
#define width 32

int main()  {

    int i,j,k,np=0,*brick,pow2,ch=0,found[width+1];
    int offset,offset2,s1,s2,good;
    long long int *dp,*temp,sum;
    
    pow2=1<<(width/2);
    brick=(int*)(malloc)(pow2*sizeof(int));
    for(i=0;i<pow2;i++)  {
        j=i;
        sum=0;
        while(sum<width)  {
            if(j&1)  sum+=2;
            else  sum+=3;
            j>>=1;
        }
        if((sum==width)&&(j==0))  {
           brick[np]=i;
           np++;
        }
    }
    dp=(long long int*)(malloc)(np*sizeof(long long int));
    temp=(long long int*)(malloc)(np*sizeof(long long int));
    for(i=0;i<np;i++)  dp[i]=1;
    for(i=0;i<=width;i++)  found[i]=-1;
    for(i=1;i<height;i++)  {
        for(j=0;j<np;j++)  temp[j]=dp[j],dp[j]=0;
        for(j=0;j<np;j++)  {
            for(k=0;k<np;k++)  {
                offset=brick[j];
                offset2=brick[k];
                s1=0,s2=0;
                ch++;
                while(s1<width)  {
                      if(offset&1)  s1+=2;
                      else  s1+=3;
                      found[s1]=ch;
                      offset>>=1;
                }
                good=1;
                while(s2<width)  {
                      if(offset2&1)  s2+=2;
                      else  s2+=3;
                      if((s2<width)&&(found[s2]==ch))  {
                          good=0;
                          break;
                      }
                      offset2>>=1;
                }
                if(good)  dp[j]+=temp[k];
    }}}
    sum=0;
    for(i=0;i<np;i++)  sum+=dp[i];
    printf("%I64d\n",sum);
    return 0;
}
Java:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;

/**
 *
 * @author fra
 */
public class Problem215{

    
    
    
    /**
     * Generates all combinations of a row of 2x1, 3x1 bricks starting from position pos
     * @param r    the row of bricks up to now
     * @param rows stores all rows
     * @param pos  up to where the row has been generated
     * @param n    the length of the row
     */
    public static final void generateRows(BitSet r, Collection<BitSet> rows, int pos, int n){
        
        //Last brick
        if(pos >= n-4){
            if(pos == n-4 || pos == n-3){
                rows.add(r);
            }
            return;
        }
        
        //Adds a 2x1 brick
        BitSet r2 = (BitSet) r.clone();
        r2.set(pos+2);
        generateRows(r2, rows, pos+2,n);
        
        //Adds a 3x1 brick
        BitSet r3 = (BitSet) r.clone();
        r3.set(pos+3);
        generateRows(r3, rows, pos+3,n);
        
        return;
    }
    
    
    
    /**
     * Calculates the possible arrangements of 2x1, 3x1 bricks
     * @param n length of the row
     * @param m number of rows
     * @return the possible arrangements of bricks
     */
    public static final long w(int n, int m) {
        
        
        BitSet cracks = new BitSet(n-1);
        ArrayList<BitSet> rows = new ArrayList<BitSet>();
        long[] swap;
        
        generateRows(cracks, rows, -1,n);
        
        //Checks which rows can be connected
        boolean[][] canConnect = new boolean[rows.size()][rows.size()];
        for (int i = 0; i < rows.size(); i++) {
            for (int j = 0; j <= i; j++) {
                canConnect[i][j] = ! rows.get(i).intersects(rows.get(j));
                canConnect[j][i] = canConnect[i][j];
            }
        }

        //First row can be any
        long[] c = new long[rows.size()];
        Arrays.fill(c, 1);
        long[] nc = new long[rows.size()];
        
        //Adds a second row
        for (int i = 1; i < m; i++) {
            Arrays.fill(nc, 0); 
            for (int j = 0; j < nc.length; j++) {
                for (int k = 0; k < nc.length; k++) {
                    if(canConnect[j][k])
                        nc[k] += c[j];
                }
            }
            
            //Prepares for next row
            swap = c;
            c = nc;
            nc = swap;
        }

        
        //Sums up the result
        long sum =0;
        for (long l : c) sum += l;
        return sum;
    }
    
    public static final void main(String args[]){
        int n = 32;
        int m = 10;
        System.out.println("W(" + n + "," + m +") = " +  w(n,m));
    }

}
Matlab:

function pe_215
N=32;
P=10;

% list of all walls
L=generate_walls({[]},N);

% easier representation
M=zeros(numel(L),N);
for k=1:numel(L)
    M(k,cumsum(L{k}))=1;
end;

% store possible children (fitting walls)
for k=1:numel(L)
    idx=M*(M(k,:)');
    L{k}=find(idx==1);
end;
L=[L {1:numel(L)}];

% at each stage, replace each node by their children 
% (number thereof, actually)
idx=zeros(1,numel(L)); %number of each wall used at a particular stage
idx(end)=1;
for p=1:P
    idx2=zeros(1,numel(L));
    for k=1:numel(L)
        idx2(L{k})=idx2(L{k})+idx(k);
    end;
    idx=idx2;
end;

%result
int2str(sum(idx))

function L2=generate_walls(L,n)
    L2={};
    for k=1:numel(L)
        s=sum(L{k});
        switch s
            case n,
                L2=[L2 L{k}];
            case n-1
                %impossible
            case n-2
                L2=[L2 [L{k} 2]];
            case n-3
                L2=[L2 [L{k} 3]];
            otherwise
                L2=[L2 generate_walls({[L{k} 2]},n)];
                L2=[L2 generate_walls({[L{k} 3]},n)];
        end;
    end;
 
Maple:
> hmwt:=proc(n,t)
> option remember;
> local T,i;
> if n=0 then return [0] fi;
> if n<=1 or member(n,t) then return false fi;
> T:=NULL;
> if hmwt(n-2,t)<>false then for i in hmwt(n-2,t) do T:=T,[n-2,i[]] od fi;
> if hmwt(n-3,t)<>false then for i in hmwt(n-3,t) do T:=T,[n-3,i[]] od fi;
> [T];
> end:
> 
> tot:=proc(n,m,t)
> option remember;
> if m=0 then return 1 fi;
> add(tot(n,m-1,y),y in hmwt(n,t));
> end:
> 
> tot(9,3,[NULL]);
                                  8

> tot(32,10,[NULL]);

                           806844323190414
Mathematica:

k = 32;
n = 10;
ClearAll[tiles]
tiles[0] := {{}}
tiles[1] := {}
tiles[2] := {{2}}
tiles[3] := {{3}}
addtile[s_, v_] := Map[Sort[Append[#, Last[#] + v]] &, s]
tiles[n_] /; n > 3 := 
 tiles[n] = Union[addtile[tiles[n - 2], 2], addtile[tiles[n - 3], 3]]
tobinary[s_] := Total[Map[2^(# - 2) &, s]]
v = tobinary /@ Most /@ tiles[k];
m = Length[v]
c = Table[Boole[BitAnd[v[[i]], v[[j]]] == 0], {i, m}, {j, m}];
Total[Nest[c.# &, ConstantArray[1, m], n - 1]]

Delphi:
{----------------------------------------------------------------------}
Procedure Pb215;
Var T: Array of String[32]; nl,nb: Byte; i: Integer; s: Int64; sl: Tstringlist; w: TPtrInt64;

   {===== ==== ==== ==== ==== ====}
   Procedure FillWall(const zl, zll: Byte; Var zs: Int64);
   Var b,wll: Byte; wzs: Int64; wzi: Integer; w1,w2: TPtrInt64;
   Begin
   For b := 2 to 3 Do Begin
      wll := zll+b;
      If (wll = nb) Then begin
          If (zl = nl) Then
             inc(zs)
          Else
          If sl.find(Inttostr(zl)+Copy(T[zl],1,nb),wzi) then Begin
             w1 := Pointer(sL.Objects[wzi]); zs := zs + w1.N;
             End
          Else Begin
             wzs := 0; FillWall(zl+1, 0, wzs); zs := zs + wzs;
             w2 := New(TPtrInt64); w2.N := wzs; sl.addobject(Inttostr(zl)+Copy(T[zl],1,nb),Pointer(w2));
             End;
          End
      Else
      If (wll <> nb-1) And (T[zl-1][wll] = 'N') Then Begin
         T[zl][wll] := 'O'; FillWall(zl, wll, zs); T[zl][wll] := 'N';
         End;
      End;
   End;
   {===== ==== ==== ==== ==== ====}

Begin
nl := 10; nb := 32;
sl := Tstringlist.Create; sl.Sorted := True;
Setlength(T, nl+1);
For i := 0 to nl Do Begin
   T[i] := 'NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN'; T[i][nb+1] := 'O'; T[i][nb+2] := 'O';
   End;
Try
s := 0; FillWall(1,0,s); mmo_res := Inttostr(s);
Finally
   Setlength(T, 0);
   For i := 0 to sl.count-1 do
      If sl.Objects[i] <> NIL Then Begin
         w := Pointer(sl.Objects[i]); Dispose(w); sl.Objects[i] := NIL;
         End;
   sl.free;
   End;
End;