High score in grid walk

There is an interesting game named one person game. It is played on a m*n grid. There is an non-negative integer in each grid cell. You start with a score of 0. You cannot enter a cell with an integer 0 in it. You can start and end the game at any cell you want (of course the number in the cell cannot be 0). At each step you can go up, down, left and right to the adjacent grid cell. The score you can get at last is the sum of the numbers on your path. But you can enter each cell at most once.

The aim of the game is to get your score as high as possible.

Input:
The first line of input is an integer T the number of test cases. The first line of each test case is a single line containing 2 integers m and n which is the number of rows and columns in the grid. Each of next the m lines contains n space-separated integers D indicating the number in the corresponding cell

Output:
For each test case output an integer in a single line which is maximum score you can get at last.

Constraints:
T is less than 7.
D is less than 60001.
m and n are less than 8.

Sample Input:

4
1 1
5911
1 2
10832 0
1 1
0
4 1
0
8955
0
11493

Sample Output:

5911
10832
0
11493

I tried it but my approach is working very slow for a 7x7 grid.I am trying to access every possible path of the grid recursively and comparing the sum of every path.Below is my code

#include<iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;

int max(int a,int b,int c, int d)
{
int max = a;
if(b>max)
    max = b;
if(c>max)
    max = c;
if(d>max)
    max = d;
return max;
}

int Visit_Component( int (*A)[8], int Visit[8][8], int m,int n , int row, int col)
{

if ( ( row >= m ) || (col >= n )  || (col < 0) || (row < 0)  || A[row][col] == 0         || Visit[row][col] == 1 )
{
    return 0;
}
else
{

    Visit[row][col] = 1;
    int a= 0,b=0,c=0,d=0,result =0;
    a = Visit_Component( A, Visit,m,n, row+1, col);
    b = Visit_Component( A, Visit,m,n, row, col +1);
    c = Visit_Component( A, Visit,m,n, row, col -1);
    d = Visit_Component( A, Visit,m,n, row-1, col );
    Visit[row][col] = 0;
    result  = A[row][col] + max(a,b,c,d);
    return result;
}
}

int main(){

int T;
scanf("%d",&T);
for(int k =0; k<T;k++)
{
    int N ;
    int M;
    int count = 0;
    int maxcount = 0;
    scanf("%d %d",&M,&N);
    int C[8][8];
    int visit[8][8];
    for(int i = 0; i < M; i++)
        for(int j = 0; j < N; j++)
        {
            scanf("%d",&C[i][j]);
            visit[i][j] = 0;
        }
    for( int i= 0 ; i< M ; i++ )
    {
        for( int j =0; j< N ; j++ )
        {

            count  = Visit_Component( C, visit,M,N, i, j);
            if(count > maxcount)
            {
                maxcount  = count;
            }
        }
    }
    printf("%dn",maxcount);
}
return 0;
}

Please suggest me how to optimize this approach or a better algorithm.


As Wikipedia article on Travelling salesman problem suggests, there are exact algorithms, solving this task quickly. But it is hard to find any. And they are, most likely, complicated.

As for optimizing OP's approach, there are several possibilities.

It's easier to start with simple micro-optimization: condition Visit[row][col] == 1 is satisfied with highest probability, so it should come first.

Also it is reasonable to optimize branch-and-bound algorithm with dynamic programming to avoid some repeated calculations. Memorizing calculation results in simple hash table for the cases of up to 19 visited cells improves performance by more than 25% (and more may be expected for some improved hash table). Here is the modified code snippet:

#include<iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;

int max(int a,int b,int c, int d)
{
  int max = a;
  if(b>max)
    max = b;
  if(c>max)
    max = c;
  if(d>max)
    max = d;
  return max;
}

typedef unsigned long long ull;
static const int HS = 10000019;
static const int HL = 20;
struct HT {
  ull v;
  int r;
  int c;
};
HT ht[HS] = {0};

int Visit_Component(
  int (*A)[8], ull& Visit, int m,int n , int row, int col, int x)
{

  if ( (Visit & (1ull << (8*row+col))) || ( row >= m ) || (col >= n )  ||
    (col < 0) || (row < 0)  || A[row][col] == 0)
  {
    return 0;
  }
  else
  {
    if (x < HL)
    {
      HT& h = ht[(Visit+4*row+col)%HS];
      if (h.v == Visit && h.r == row && h.c == col)
        return 0;
    }

    Visit |= (1ull << (8*row+col));
    int a= 0,b=0,c=0,d=0,result =0;
    a = Visit_Component( A, Visit,m,n, row+1, col, x+1);
    b = Visit_Component( A, Visit,m,n, row, col +1, x+1);
    c = Visit_Component( A, Visit,m,n, row, col -1, x+1);
    d = Visit_Component( A, Visit,m,n, row-1, col , x+1);
    Visit &= ~(1ull << (8*row+col));
    result  = A[row][col] + max(a,b,c,d);

    if (x < HL)
    {
      HT& h = ht[(Visit+4*row+col)%HS];
      h.v = Visit;
      h.r = row;
      h.c = col;
    }

    return result;
  }
}

int main(){

  int T;
  scanf("%d",&T);
  for(int k =0; k<T;k++)
  {
    int N ;
    int M;
    int count = 0;
    int maxcount = 0;
    scanf("%d %d",&M,&N);
    int C[8][8];
    ull visit = 0;
    for(int i = 0; i < M; i++)
        for(int j = 0; j < N; j++)
        {
            scanf("%d",&C[i][j]);
        }
    for( int i= 0 ; i< M ; i++ )
    {
        for( int j =0; j< N ; j++ )
        {

            count  = Visit_Component( C, visit,M,N, i, j, 0);
            if(count > maxcount)
            {
                maxcount  = count;
            }
        }
    }
    printf("%dn",maxcount);
  }
  return 0;
}

And much more improvements may be done by pre-processing the input matrix. If there are no zeros in the matrix or if there is only one zero in the corner, you may just sum all the values.

If there is only one zero value (not in the corner), at most one non-zero value should be excluded from the sum. If you invent an algorithm, that determines the subset of cells, from which one of the cells must be removed, you can just select the smallest value from this subset.

If there are two or more zero values, use branch-and-bound algorithm: in this case it is about 20 times faster, because each zero value in input matrix means approximately fivefold speed increase.


One optimization that I can think of is to apply Dijkstra's algorithm. This algorithm will give you a minimum (in your case maximum) path for a particular source node to all destination nodes.

In this example, the first step would be to build a graph.

And because you don't know the source node to start at, you will have to apply Dijkstra's algorithm for each node in the grid. The time complexity will be better than your recursion method because for a particular source node, when finding a maximum path Dijkstra's algorithm does not go through all the possible paths.


#include<iostream>
#include<vector>

using namespace std;
vector<vector<int> >A;
vector<vector<bool> >test;
vector<vector<bool> >test1;
int sum_max=0;
int m,n;
vector<vector<bool> > stamp;
void color1(int i,int j,vector<vector<bool> >temp_vector,vector<vector<bool> > st,int summ){

   temp_vector[i][j]=false;summ+=A[i][j];st[i][j]=true;
 //1.1
  if(i+1<m && temp_vector[i+1][j]){
   if(test1[i+1][j]){
                     if(sum_max<(summ)){sum_max=summ;stamp=st;}
                     }    
else{color1(i+1,j,temp_vector,st,summ);}
}
   //1.2
   if(i+1<m){if(!temp_vector[i+1][j]){ if(sum_max<(summ)){sum_max=summ;}}} 
   if(i+1>=m){if(sum_max<(summ)){sum_max=summ;}} 

    //2
 if(i-1>=0 && temp_vector[i-1][j]){
          if(test1[i-1][j]){
                     if(sum_max<(summ)){sum_max=summ;}
                     }    
    else{ color1(i-1,j,temp_vector,st,summ);}
     }
   //2.2
   if(i-1>=0){if(!temp_vector[i-1][j]){ if(sum_max<(summ)){sum_max=summ;}}}
      if(i-1<0){if(sum_max<(summ)){sum_max=summ;}} 

     //3
     if(j+1<n && temp_vector[i][j+1]){
        if(test1[i][j+1]){
                         if(sum_max<(summ)){sum_max=summ;}
                     }    
    else{      color1(i,j+1,temp_vector,st,summ);}}
  //3.2
   if(j+1<n){if(!temp_vector[i][j+1]){ if(sum_max<(summ)){sum_max=summ;}}}
      if(j+1>=n){if(sum_max<(summ)){sum_max=summ;}} 

     //4
     if(j-1>=0 && temp_vector[i][j-1]){
        if(test1[i][j-1]){
                     if(sum_max<(summ)){sum_max=summ;}
                     }    
else{       color1(i,j-1,temp_vector,st,summ);}}
//4.2
   if(j-1>=0){if(!temp_vector[i][j-1]){ if(sum_max<(summ)){sum_max=summ;}}}
      if(j+1<0){if(sum_max<(summ)){sum_max=summ;}} 

 }


void color(int i,int j){
   test[i][j]=false;
  if(i+1<m && test[i+1][j]){
    color(i+1,j);}
     if(i-1>=0 && test[i-1][j]){
           color(i-1,j);
 }
 if(j+1<n && test[i][j+1]){
          color(i,j+1);}
 if(j-1>=0 && test[i][j-1]){color(i,j-1);}

}

int main(){
    int tc;cin>>tc;
    for(int i=0;i<tc;i++){
        int mp,np;
        cin>>mp;
        cin>>np;m=mp;n=np;A.resize(m);test.resize(m);test1.resize(m);int sum=0;
        vector<bool> ha1(m,1);
        vector<bool> ha2(n,1);
        for(int i=0;i<m;i++){A[i].resize(n);test[i].resize(n);test1[i].resize(n);
                for(int j=0;j<n;j++){
                        cin>>A[i][j];sum+=A[i][j];
                                                    test[i][j]=true;test1[i][j]=false;
                                                    if(A[i][j]==0){test[i][j]=false;ha1[i]=false;ha2[j]=false;}
                        }
                }cout<<endl;
               for(int i=0;i<m;i++){cout<<"  "<<ha1[i];} cout<<endl;
               for(int i=0;i<n;i++){cout<<"  "<<ha2[i];} cout<<endl;
              cout<<"sum "<<sum<<"n";
                int temp_sum=0;
                 for(int i=0;i<m;i++){
                                for(int j=0;j<n;j++){//if(A[i][j]<=8845){cout<<"nk "<<A[i][j]<<"  "<<(8845-A[i][j]);}
                                        if(test[i][j]){
                                                       if((i-1)>=0 && test[i-1][j] && (i+1)<m && test[i+1][j] && (j-1)>=0 && test[i][j-1] && (j+1)<n && test[i][j+1] && test[i-1][j-1] && test[i-1][j+1]&& test[i+1][j-1] && test[i+1][j+1]){
                                                                   temp_sum+=A[i][j];test1[i][j]=true;}

                                                       }
                                                     //  cout<<test1[i][j]<<"    ";
                                        }//cout<<"n";
                                        }

//         /*
                 for(int i=0;i<m;i++){
                                for(int j=0;j<n;j++){

                                        if(test1[i][j]){if(!((test1[i-1][j]||test1[i+1][j]) && (test1[i][j-1]||test1[i][j+1]))){
                                                                                         temp_sum-=A[i][j];   test1[i][j]=false;}
                                        }

                                                      //
                                                   //    cout<<test1[i][j]<<"    ";
                                        }//
                                       // cout<<"n";
                                        }
  //              */

               //cout<<"n temp_sum is "<<temp_sum<<endl;
               vector<vector<bool> > st(m,vector<bool>(n,0));st=test1;
                 for(int i=0;i<m;i++){
                                for(int j=0;j<n;j++){
                                        if(test[i][j] && (!test1[i][j])){
                                                       color1(i,j,test,st,0);

                                                       }}}

            //    cout<<"nsum is "<<(sum_max+temp_sum)<<endl<<endl;
            cout<<(sum_max+temp_sum)<<endl;
      for(int i=0;i<m;i++){
                              for(int j=0;j<n;j++){cout<<stamp[i][j]<<"  ";}    cout<<endl;}
//            cout<<max<<endl;
        A.clear();
        test.clear();
        test1.clear();
        sum_max=0;
            }


    cout<<endl;system("pause");
return 0;
}
链接地址: http://www.djcxy.com/p/10954.html

上一篇: 如何使用颜色来直观地强调光标所在的功能?

下一篇: 网格散步的高分