Sayfalar

20 Aralık 2016

Euler Projesi 208. Soru

Robot Yürüyüşü

Bir robot bir başlangıç noktasından hareketle, durduğu noktada dönmemek ve sonuçta aynı noktaya gelmek üzere, saat yönünde ya da saatin ters yönünde çizilen 1/5 lik tam açılar (72° lik yay) serisi şeklinde hareket ediyor.

Kuzeye dönük şekilde başlatılan 25 yaydan oluşan olası 70932 kapalı yoldan biri aşağıda veriliyor:


Kuzeye dönük şekilde duran bir robot, 70 yaydan oluşan kaç farklı kapalı yol izleyebilir?

Cevap: 331951449665644800

Java:
import java.util.Map;
import java.util.TreeMap;

public class Euler208 {

   public class Path implements Comparable <Path>
   {
      // number of steps to take in each direction till at origin
      public byte[] steps = new byte[5];
      // direction, 0-4
      public int rotation;
      public Path(){}
      public Path(Path p2){ set(p2); }
      // compare function for map
      public int compareTo(Path p2) {
         if( rotation != p2.rotation ) return rotation - p2.rotation;
         for( int i=0; i<5; i++ )
            if( steps[i] != p2.steps[i] ) return steps[i] - p2.steps[i];
         return 0;
      }
      // copy value from existing instance
      public void set( Path p2 ){
         for( int i=0; i<5; i++ )steps[i] = p2.steps[i];
         rotation = p2.rotation;
      }
      // extend path by a left turn
      public void growLeft(){
         steps[rotation]--;
         rotation = rotation==0 ? 4 : rotation-1;
         reduce();
      }
      // extend path by a right turn
      public void growRight(){
         rotation = rotation==4 ? 0 : rotation+1; 
         steps[rotation]--;
         reduce();
      }
      // keep all distance counts positive - add one step in each direction if not
      private void reduce(){
         if( steps[0]<0 || steps[1]<0 || steps[2]<0 || steps[3]<0 || steps[4]<0 )
         {
            ++steps[0];
            ++steps[1];
            ++steps[2];
            ++steps[3];
            ++steps[4];
         }
      }
      // check that can still solve it within d steps
      public boolean solvableIn( int d ){
         return d - (steps[0]+steps[1]+steps[2]+steps[3]+steps[4]) >= 0;
      }
   }

   final int size = 70;
   Euler208(){
      // paths of current length, each type with a count number 
      Map <Path,Long> map1 = new TreeMap <Path, Long>();
      // One path of zero length
      map1.put(new Path(), 1L);

      // lengthened paths
      Map <Path,Long> map2 = new TreeMap <Path, Long>();
      
      Path temp = new Path();   // temporary path instance

      for( int i=0; i<size; i++ ){  // lengthen up to size times
         // for each path
         for (Map.Entry <Path,Long> pair : map1.entrySet() ) {
            temp.set(pair.getKey());
            // if solvable
            if( temp.solvableIn(size-i)){
               // extend it with left curve, and add to map2
               temp.growLeft();
               addPath( map2, temp, pair.getValue() );

               // extend it with right curve, and add to map2
               temp.set(pair.getKey());
               temp.growRight();
               addPath( map2, temp, pair.getValue() );
            }
         }
         // clear out old length paths
         map1.clear();
         // swap maps, so that will next use longer paths
         Map <Path,Long> map3 = map1;
         map1 = map2;
         map2 = map3;
         System.out.println(map1.size());
      }
      // print result
      long count = map1.get(new Path());
      System.out.println("Total: "+count);
   }
   // Add c paths of type p to the map
   private void addPath( Map <Path,Long> map, Path p, long c ){
      Long old = map.get(p);
      if( old ==null ){
         map.put( new Path(p), c);
      }else{
         map.put( p, c+old );
      }
   }
}
 
C++:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define PI 3.141592653589793238462643383
#define eps 1e-6
#define n 70

typedef struct
{
    long long int offset;
    long long int count;
}List;

int compare (const void* source, const void* dest)
{
    List* listSource = (List*) source;
    List* listDest = (List*) dest;
    if((listSource->offset)>(listDest->offset))  return 1;
    return -1;
}
 
double ABS(double x)  {
    if(x<0.0)  return -x;
    return x;
}

int main()  {
    
    int i,i2,I,NUM,j,dir,dir2,num,angle,angle2,A[5];
    long long int offset,total,pow256[8];
    double x,y;
    List* myList;
    List* myList2;
    
    pow256[0]=1;
    for(i=1;i<8;i++)  pow256[i]=pow256[i-1]<<8;
    
    myList=(List*)(malloc)(1*sizeof(List));
    
    num=1;
    myList[0].count=1;
    myList[0].offset=2+127*pow256[2]+128*pow256[3]+128*pow256[4]+128*pow256[5]+128*pow256[6];
    for(I=0;I<n;I++)  {
        myList2=(List*)(malloc)(2*num*sizeof(List));
        for(i=0;i<num;i++)  {
            offset=myList[i].offset;
            dir=(offset&255)-1;
            offset>>=8;
            angle=offset&255;
            
            i2=i<<1;
            angle2=(angle+2*dir+10)%10;
            myList2[i2].offset=myList[i].offset+((angle2-angle)<<8);
            myList2[i2].count=myList[i].count;
            
            dir2=-dir;
            angle2=(angle+5+2*dir2)%10;
            myList2[i2+1].offset=myList[i].offset+(dir2-dir)+((angle2-angle)<<8);
            if(angle<5)  myList2[i2+1].offset+=2*pow256[angle+2];
            else  myList2[i2+1].offset-=2*pow256[angle+2-5];
            myList2[i2+1].count=myList[i].count;
        }
        free(myList);
        num<<=1;
        qsort(myList2,num,sizeof(List),compare);
        NUM=0;
        for(i=1;i<num;i++)  {
            if(myList2[i].offset==myList2[NUM].offset)  {
                   myList2[NUM].count+=myList2[i].count;
            }
            else  {
                   NUM++;
                   myList2[NUM].offset=myList2[i].offset;
                   myList2[NUM].count=myList2[i].count;
            }
        }
        num=NUM+1;
        myList=(List*)(malloc)(num*sizeof(List));
        for(i=0;i<num;i++)  {
             myList[i].offset=myList2[i].offset;
             myList[i].count=myList2[i].count;
        }
        free(myList2);
    }
    total=0;
    for(i=0;i<num;i++)  {
        offset=myList[i].offset;
        dir=(offset&255)-1;
        offset>>=8;
        angle=offset&255;
        for(j=0;j<5;j++)  {
            offset>>=8;
            A[j]=(offset&255)-128;
        }
        if(angle<5)  A[angle]++;
        else  A[angle-5]--;
        
        x=0.0;
        y=0.0;
        for(j=0;j<5;j++)  {
            x+=(double) A[j]*cos((double) j*2.0*PI/10.0);
            y+=(double) A[j]*sin((double) j*2.0*PI/10.0);
        }
        if((ABS(x)<eps)&&(ABS(y)<eps))  total+=myList[i].count;
    }
    printf("%I64d\n",total);
       
    return 0;
}
 
Basic:
Public Class Euler208
    Private Const Max As Long = 14
    Private Mul(4) As Long
    Private Const SPN = (Max + 1) ^ 5 - 1
    Private R(4, SPN - 1) As Long
    Private Sub Euler208_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Dim t As New System.Diagnostics.Stopwatch
        t.Start()

        Dim L As Long, I As Long
        For L = 0 To (SPN - 1)
            For I = 0 To 4
                R(I, L) = -1
            Next
        Next

        For I = 0 To 4
            Mul(I) = (Max + 1) ^ I
        Next
        tResult.Text = Solve(0, 0)

        Me.Text = "Solved Euler 208 in " & (t.ElapsedMilliseconds / 1000) & "s"
    End Sub
    Private Function Solve(ByVal Num As Long, ByVal d As Integer) As Long

        If Num = SPN Then
            If d = 0 Then Return 1 Else Return 0
        End If
        If R(d, Num) <> -1 Then Return R(d, Num)

        Dim NumB As Long, I As Long, db As Integer

        Solve = 0
        For I = 4 To 6 Step 2
            db = (d + I) Mod 5
            If (Num \ Mul(db)) Mod Mul(1) < Max Then
                NumB = Num + Mul(db)
                Solve = Solve + Solve(NumB, db)
            End If
        Next
        R(d, Num) = Solve
    End Function

End Class
 
Mathematica:
n = 4;
Clear[F,x];
For[i=0,i<=n,i++,
 e[i]=PadRight[CoefficientList[PolynomialRemainder[
  x^i,Cyclotomic[n,x],x],x],EulerPhi@n];
];
zero=Array[0&,EulerPhi@n];
F[m_,A_,i_]:= F[m, A, i] = If[m==0,
 If[A==zero && i==0, 1, 0],
 Expand[x F[m-1,A+e[i+1],Mod[i+1,n]] + F[m-1,A+e[i],Mod[i-1,n]]]
];
 
Matlab:
n=14;
nsteps=n*5;
npos=5;
nvec=zeros(npos,n+1,n+1,n+1,n+1,n+1);
nvec(1,2,1,1,1,1)=1;
for i=2:nsteps
    nvecnew=zeros(npos,n+1,n+1,n+1,n+1,n+1);
    for l=1:n
        for j=1:npos
            if j==1
                nvecnew(j,l+1,:,:,:,:)=nvec(5,l,:,:,:,:);
                nvecnew(j,l+1,:,:,:,:)=nvecnew(j,l+1,:,:,:,:)+nvec(j+1,l,:,:,:,:);
            elseif j==2
                nvecnew(j,:,l+1,:,:,:)=nvec(j-1,:,l,:,:,:);
                nvecnew(j,:,l+1,:,:,:)=nvecnew(j,:,l+1,:,:,:)+nvec(j+1,:,l,:,:,:);
            elseif j==3
                nvecnew(j,:,:,l+1,:,:)=nvec(j-1,:,:,l,:,:);
                nvecnew(j,:,:,l+1,:,:)=nvecnew(j,:,:,l+1,:,:)+nvec(j+1,:,:,l,:,:);
            elseif j==4
                nvecnew(j,:,:,:,l+1,:)=nvec(j-1,:,:,:,l,:);
                nvecnew(j,:,:,:,l+1,:)=nvecnew(j,:,:,:,l+1,:)+nvec(j+1,:,:,:,l,:);
            else
                nvecnew(j,:,:,:,:,l+1)=nvec(j-1,:,:,:,:,l);
                nvecnew(j,:,:,:,:,l+1)=nvecnew(j,:,:,:,:,l+1)+nvec(1,:,:,:,:,l);
            end
        end
    end
    nvec=nvecnew; 
end
2*nvec(5,n+1,n+1,n+1,n+1,n+1)