#include <ctime>
#include <vector>
#include <cstdio>
struct PMatrix {
int nsize; // Size of Matrix = nsize * nsize.
int psize; // PSize = path length.
std:: vector < int > data; // Values of cells.
std:: vector < bool > mark; // Mark means cell already visited.
std:: vector < int > seq; // Workspace for Path
std:: vector < int > bestseq; // Best-known path so far.
int BestVal; // Value of best-known path so far.
int si, sj; // Starting coordinates.
// Coordinates are linearized for easier movement. Element (i, j) = Element(ij), with ij = i * n + j.
int l( int i, int j) const { return i* nsize + j; }
// Movement: Up/Down changes i, Left/Right changes j. Provides wrap-around.
int up( int i, int j) const { return l( ( i+ 1 ) % nsize, j) ; }
int dw( int i, int j) const { return l( ( i- 1 + nsize) % nsize, j) ; }
int ri( int i, int j) const { return l( i, ( j+ 1 ) % nsize) ; }
int le( int i, int j) const { return l( i, ( j- 1 + nsize) % nsize) ; }
// Easy accessors.
int e( int ij) const { return data[ ij] ; }
int m( int ij) const { return mark[ ij] ; }
// On visit: set node, branch, unset.
void set( int ij) { mark[ ij] = true ; }
void unset( int ij) { mark[ ij] = false ; }
// Checks if node ij is visitable: value is not zero & unmarked (unvisited in current branch).
bool c( int ij) const { return ( ( bool ) e( ij) && ! mark[ ij] ) ; }
// Initialize, set starting point.
PMatrix( int n, int k, int i, int j) : nsize( n) , psize( k+ 1 ) , data( nsize* nsize) , mark( nsize* nsize, false ) , seq( psize) , bestseq( psize) , BestVal( 0 ) , si( i) , sj( j) {
seq[ 0 ] = l( i, j) ;
set( l( i, j) ) ;
}
// Calculates total value of current finished path.
int cvalue( ) {
int v = 0 ;
for ( unsigned i = 0 ; i < seq.size ( ) ; ++ i) {
int ij = seq[ i] ;
v + = e( ij) ;
}
return v;
}
// Print path and value.
void PrintBest( ) {
int v = 0 ;
for ( unsigned i = 0 ; i < bestseq.size ( ) ; ++ i) {
int ij = bestseq[ i] ;
v + = e( ij) ;
printf ( "Visit (%d, %d) for value %d.\n " , ij/ nsize, ij% nsize, e( ij) ) ;
}
printf ( "Total value: %d\n " , v) ;
}
// Solve recursively: choose step k starting from (ci, cj).
void Solve( int k, int ci, int cj) {
// Full path constructed: check and end.
if ( k == psize) {
// Calculate Value
int val = cvalue( ) ;
// If Val > BestVal, Save();
if ( val > BestVal) {
BestVal = val;
std:: copy ( seq.begin ( ) , seq.end ( ) , bestseq.begin ( ) ) ;
}
}
// Otherwise, set and branch. Bounds can be added.
else /*if ((psize-k) * MaxElementValue > BestVal)*/ {
// Try 4 moves and branch.
if ( c( up( ci, cj) ) ) {
seq[ k] = up( ci, cj) ;
set( up( ci, cj) ) ;
Solve( k+ 1 , ( ci + 1 ) % nsize, cj) ;
unset( up( ci, cj) ) ;
}
if ( c( dw( ci, cj) ) ) {
seq[ k] = dw( ci, cj) ;
set( dw( ci, cj) ) ;
Solve( k+ 1 , ( ci + - 1 + nsize) % nsize, cj) ;
unset( dw( ci, cj) ) ;
}
if ( c( ri( ci, cj) ) ) {
seq[ k] = ri( ci, cj) ;
set( ri( ci, cj) ) ;
Solve( k+ 1 , ci, ( cj + 1 ) % nsize) ;
unset( ri( ci, cj) ) ;
}
if ( c( le( ci, cj) ) ) {
seq[ k] = le( ci, cj) ;
set( le( ci, cj) ) ;
Solve( k+ 1 , ci, ( cj - 1 + nsize) % nsize) ;
unset( le( ci, cj) ) ;
}
}
return ;
}
} ;
int main( ) {
PMatrix p( 5 , 20 , 2 , 2 ) ;
int vals[ 5 * 5 ] = { 9 , 1 , 3 , 1 , 9 , 6 , 3 , 2 , 4 , 1 , 0 , 7 , 0 , 7 , 7 , 5 , 4 , 9 , 4 , 9 , 7 , 9 , 1 , 5 , 5 } ;
for ( int ij = 0 ; ij < 5 * 5 ; ++ ij) {
p.data [ ij] = vals[ ij] ;
}
clock_t a( clock ( ) ) ;
p.Solve ( 1 , 2 , 2 ) ;
clock_t e( clock ( ) ) ;
p.PrintBest ( ) ;
printf ( "Number of ticks: %u.\n " , ( e- a) ) ;
return 0 ;
}
I2luY2x1ZGUgPGN0aW1lPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8Y3N0ZGlvPgoKc3RydWN0IFBNYXRyaXggewoJaW50IG5zaXplOwkJCQkJLy8gU2l6ZSBvZiBNYXRyaXggPSBuc2l6ZSAqIG5zaXplLgoJaW50IHBzaXplOwkJCQkJLy8gUFNpemUgPSBwYXRoIGxlbmd0aC4KCXN0ZDo6dmVjdG9yPGludD4gZGF0YTsJCS8vIFZhbHVlcyBvZiBjZWxscy4KCXN0ZDo6dmVjdG9yPGJvb2w+IG1hcms7CQkvLyBNYXJrIG1lYW5zIGNlbGwgYWxyZWFkeSB2aXNpdGVkLgoKCXN0ZDo6dmVjdG9yPGludD4gc2VxOwkJLy8gV29ya3NwYWNlIGZvciBQYXRoCglzdGQ6OnZlY3RvcjxpbnQ+IGJlc3RzZXE7CS8vIEJlc3Qta25vd24gcGF0aCBzbyBmYXIuCgoJaW50IEJlc3RWYWw7CQkJCS8vIFZhbHVlIG9mIGJlc3Qta25vd24gcGF0aCBzbyBmYXIuCgoJaW50IHNpLCBzajsJCQkJCS8vIFN0YXJ0aW5nIGNvb3JkaW5hdGVzLgoKCS8vIENvb3JkaW5hdGVzIGFyZSBsaW5lYXJpemVkIGZvciBlYXNpZXIgbW92ZW1lbnQuIEVsZW1lbnQgKGksIGopID0gRWxlbWVudChpaiksIHdpdGggaWogPSBpICogbiArIGouCglpbnQgbChpbnQgaSwgaW50IGopIGNvbnN0IHsgcmV0dXJuIGkqbnNpemUgKyBqOyB9CgkvLyBNb3ZlbWVudDogVXAvRG93biBjaGFuZ2VzIGksIExlZnQvUmlnaHQgY2hhbmdlcyBqLiBQcm92aWRlcyB3cmFwLWFyb3VuZC4KCWludCB1cChpbnQgaSwgaW50IGopIGNvbnN0IHsgcmV0dXJuIGwoKGkrMSklbnNpemUsIGopOyB9CglpbnQgZHcoaW50IGksIGludCBqKSBjb25zdCB7IHJldHVybiBsKChpLTEgKyBuc2l6ZSklbnNpemUsIGopOyB9CglpbnQgcmkoaW50IGksIGludCBqKSBjb25zdCB7IHJldHVybiBsKGksIChqKzEpJW5zaXplKTsgfQoJaW50IGxlKGludCBpLCBpbnQgaikgY29uc3QgeyByZXR1cm4gbChpLCAoai0xK25zaXplKSVuc2l6ZSk7IH0KCgkvLyBFYXN5IGFjY2Vzc29ycy4KCWludCBlKGludCBpaikgY29uc3QgeyByZXR1cm4gZGF0YVtpal07IH0KCWludCBtKGludCBpaikgY29uc3QgeyByZXR1cm4gbWFya1tpal07IH0KCS8vIE9uIHZpc2l0OiBzZXQgbm9kZSwgYnJhbmNoLCB1bnNldC4KCXZvaWQgc2V0KGludCBpaikgeyBtYXJrW2lqXSA9IHRydWU7IH0KCXZvaWQgdW5zZXQoaW50IGlqKSB7IG1hcmtbaWpdID0gZmFsc2U7IH0KCS8vIENoZWNrcyBpZiBub2RlIGlqIGlzIHZpc2l0YWJsZTogdmFsdWUgaXMgbm90IHplcm8gJiB1bm1hcmtlZCAodW52aXNpdGVkIGluIGN1cnJlbnQgYnJhbmNoKS4KCWJvb2wgYyhpbnQgaWopIGNvbnN0IHsgcmV0dXJuICgoYm9vbCllKGlqKSAmJiAhbWFya1tpal0pOyB9CgoJLy8gSW5pdGlhbGl6ZSwgc2V0IHN0YXJ0aW5nIHBvaW50LgoJUE1hdHJpeChpbnQgbiwgaW50IGssIGludCBpLCBpbnQgaikgOiBuc2l6ZShuKSwgcHNpemUoaysxKSwgZGF0YShuc2l6ZSpuc2l6ZSksIG1hcmsobnNpemUqbnNpemUsIGZhbHNlKSwgc2VxKHBzaXplKSwgYmVzdHNlcShwc2l6ZSksIEJlc3RWYWwoMCksIHNpKGkpLCBzaihqKSB7CgkJc2VxWzBdID0gbChpLCBqKTsKCQlzZXQobChpLCBqKSk7Cgl9CgoJLy8gQ2FsY3VsYXRlcyB0b3RhbCB2YWx1ZSBvZiBjdXJyZW50IGZpbmlzaGVkIHBhdGguCglpbnQgY3ZhbHVlKCkgewoJCWludCB2ID0gMDsKCQlmb3IgKHVuc2lnbmVkIGkgPSAwOyBpIDwgc2VxLnNpemUoKTsgKytpKSB7CgkJCWludCBpaiA9IHNlcVtpXTsKCQkJdiArPSBlKGlqKTsKCQl9CgkJcmV0dXJuIHY7Cgl9CgoJLy8gUHJpbnQgcGF0aCBhbmQgdmFsdWUuCgl2b2lkIFByaW50QmVzdCgpIHsKCQlpbnQgdiA9IDA7CgkJZm9yICh1bnNpZ25lZCBpID0gMDsgaSA8IGJlc3RzZXEuc2l6ZSgpOyArK2kpIHsKCQkJaW50IGlqID0gYmVzdHNlcVtpXTsKCQkJdiArPSBlKGlqKTsKCQkJcHJpbnRmKCJWaXNpdCAoJWQsICVkKSBmb3IgdmFsdWUgJWQuXG4iLCBpai9uc2l6ZSwgaWolbnNpemUsIGUoaWopKTsKCQl9CgkJcHJpbnRmKCJUb3RhbCB2YWx1ZTogJWRcbiIsIHYpOwoJfQoKCS8vIFNvbHZlIHJlY3Vyc2l2ZWx5OiBjaG9vc2Ugc3RlcCBrIHN0YXJ0aW5nIGZyb20gKGNpLCBjaikuCgl2b2lkIFNvbHZlKGludCBrLCBpbnQgY2ksIGludCBjaikgewoJCS8vIEZ1bGwgcGF0aCBjb25zdHJ1Y3RlZDogY2hlY2sgYW5kIGVuZC4KCQlpZiAoayA9PSBwc2l6ZSkgewoJCQkvLyBDYWxjdWxhdGUgVmFsdWUKCQkJaW50IHZhbCA9IGN2YWx1ZSgpOwoJCQkvLyBJZiBWYWwgPiBCZXN0VmFsLCBTYXZlKCk7IAoJCQlpZiAodmFsID4gQmVzdFZhbCkgewoJCQkJQmVzdFZhbCA9IHZhbDsKCQkJCXN0ZDo6Y29weShzZXEuYmVnaW4oKSwgc2VxLmVuZCgpLCBiZXN0c2VxLmJlZ2luKCkpOwoJCQl9CgkJfQoJCS8vIE90aGVyd2lzZSwgc2V0IGFuZCBicmFuY2guIEJvdW5kcyBjYW4gYmUgYWRkZWQuCgkJZWxzZSAvKmlmICgocHNpemUtaykgKiBNYXhFbGVtZW50VmFsdWUgPiBCZXN0VmFsKSovIHsKCgkJCS8vIFRyeSA0IG1vdmVzIGFuZCBicmFuY2guCgkJCWlmIChjKHVwKGNpLCBjaikpKSB7CgkJCQlzZXFba10gPSB1cChjaSwgY2opOwoJCQkJc2V0KHVwKGNpLCBjaikpOwoJCQkJU29sdmUoaysxLCAoY2kgKyAxKSVuc2l6ZSwgY2opOwoJCQkJdW5zZXQodXAoY2ksIGNqKSk7CgkJCX0KCQkJaWYgKGMoZHcoY2ksIGNqKSkpIHsKCQkJCXNlcVtrXSA9IGR3KGNpLCBjaik7CgkJCQlzZXQoZHcoY2ksIGNqKSk7CgkJCQlTb2x2ZShrKzEsIChjaSArIC0xICsgbnNpemUpJW5zaXplLCBjaik7CgkJCQl1bnNldChkdyhjaSwgY2opKTsKCQkJfQoJCQlpZiAoYyhyaShjaSwgY2opKSkgewoJCQkJc2VxW2tdID0gcmkoY2ksIGNqKTsKCQkJCXNldChyaShjaSwgY2opKTsKCQkJCVNvbHZlKGsrMSwgY2ksIChjaiArIDEpJW5zaXplKTsKCQkJCXVuc2V0KHJpKGNpLCBjaikpOwoJCQl9CgkJCWlmIChjKGxlKGNpLCBjaikpKSB7CgkJCQlzZXFba10gPSBsZShjaSwgY2opOwoJCQkJc2V0KGxlKGNpLCBjaikpOwoJCQkJU29sdmUoaysxLCBjaSwgKGNqIC0gMSArIG5zaXplKSVuc2l6ZSk7CgkJCQl1bnNldChsZShjaSwgY2opKTsKCQkJfQoJCX0KCQlyZXR1cm47Cgl9CgoKfTsKCmludCBtYWluKCkgewoKCVBNYXRyaXggcCg1LCAyMCwgMiwgMik7CglpbnQgdmFsc1s1KjVdID0geyAgOSwgIDEsICAzLCAgMSwgIDksICA2LCAgMywgIDIsICA0LCAgMSwgIDAsICA3LCAgMCwgNywgIDcsICA1LCAgNCwgIDksICA0LCAgOSwgIDcsICA5LCAgMSwgIDUsICA1fTsKCWZvciAoaW50IGlqID0gMDsgaWogPCA1KjU7ICsraWopIHsKCQlwLmRhdGFbaWpdID0gdmFsc1tpal07Cgl9CgljbG9ja190IGEoY2xvY2soKSk7CglwLlNvbHZlKDEsIDIsIDIpOwoJY2xvY2tfdCBlKGNsb2NrKCkpOwoJcC5QcmludEJlc3QoKTsKCXByaW50ZigiTnVtYmVyIG9mIHRpY2tzOiAldS5cbiIsIChlLWEpKTsKCXJldHVybiAwOwp9